プロジェクト

全般

プロフィール

操作

第9章 データ型とアルゴリズム

9.1 ソート sorted, sort, operator

関数、メソッド 解説 戻り値
sorted(iterable, *, key=None, reverse=False) イテラブルを引数で受け取り、ソートした結果を返す list
reversed(seq) 引数のシーケンスを逆順にした結果を返す イテレーター (reverse iterator)
list.sort(*, key=Noen, reverse=False) リストをソートした結果に変更する None
list.reverse() リストを逆順にした結果に変更する None
  • sorted() 関数

    • iterable ソート対象のイテラブルオブジェクト
    • key ソートキーを取得する呼び出し可能オブジェクト
    • reverse True:降順ソート、False:昇順ソート
    • 戻り値 リスト
    >>> lt1
    [3, 4, 1, 3, 0, 5, 1, 3, 0, 0]
    >>> sorted(lt1)
    [0, 0, 0, 1, 1, 3, 3, 3, 4, 5]
    >>> lt2 = [3, 4, 2.2, -4, 1]
    >>> lt2
    [3, 4, 2.2, -4, 1]
    >>> sorted(lt2)
    [-4, 1, 2.2, 3, 4]
    >>> sorted(["yen", "dollar", "euro"])
    ['dollar', 'euro', 'yen']
    >>> lt3 = [2, 0, "ABC"]  # 文字列と数値は比較できないのでソートはエラー
    >>> sorted(lt3)
    Traceback (most recent call last):
      File "<python-input-26>", line 1, in <module>
        sorted(lt3)
        ~~~~~~^^^^^
    TypeError: '<' not supported between instances of 'str' and 'int'
    
  • リスト以外のイテラブルの例

    >>> sorted((3, 5, 1.5, 4, 100, 2, 4))
    [1.5, 2, 3, 4, 4, 5, 100]                     # タプル
    >>> sorted({"c": 2, "a": 4, "b": 0})
    ['a', 'b', 'c']                               # 辞書はキーのリストに
    >>> sorted({"c": 2, "a": 4, "b": 0}.items())  
    [('a', 4), ('b', 0), ('c', 2)]                # 辞書をタプルイテラブルにすれば値も取得できる
    >>> sorted({5, 4, 1, 4, 9})
    [1, 4, 5, 9]                                  # 集合
    >>> sorted("SmithはPy3できますか")             # 文字列は一文字ずつ
    ['3', 'P', 'S', 'h', 'i', 'm', 't', 'y', '', '', '', '', '', '']
    
  • reversed() 関数

    • seq シーケンス型オブジェクト (※順番を持つコンテナー)
    • 戻り値 イテレーター (reverse iterator)
    >>> seq
    [6, 1, 10, 3, 0]
    >>> rev_seq = reversed(seq)
    >>> rev_seq
    <list_reverseiterator object at 0x0000016A5E2E6EF0>  # イテレーター
    >>> list(rev_seq)  # リストに変換
    [0, 3, 10, 1, 6]   # 逆順になっている
    >>> list(rev_seq)  # イテレーターなので、全部取得後は空
    []
    >>> seq
    [6, 1, 10, 3, 0]   # 元のシーケンスはそのまま
    
  • リストのメソッド sort(), reverse()

    • リストのメソッド sort(), reverse() は、破壊的操作 であり、元のリストを変更する

    • (sort() のみ) key, reverse sorted() と同じ

    • 戻り値 None

    >>> lt4
    [1, 0, 4, 2, 2, 3]
    >>> lt4.sort()  # ソート
    >>> lt4
    [0, 1, 2, 2, 3, 4]
    >>> lt5
    [8, 7, 4, 8, 2, 7]
    >>> lt5.reverse()  # 逆順
    >>> lt5
    [7, 2, 8, 4, 7, 8]
    >>> lt6
    [8, 0, 2, 4, 10, 2]
    >>> lt6.sort(reverse=True)  # 降順ソート
    >>> lt6
    [10, 8, 4, 2, 2, 0]
    
  • key 引数

    • key を指定しない場合は、要素をそのまま < (小なり) で比較する
    • key に呼び出し可能オブジェクトを設定すると、ソート対象要素それぞれを変換した結果に対して < を適用してソートする
    >>> seq_str = ["B", "D", "a", "c"]
    >>> sorted(seq_str)                 # そのままソート
    ['B', 'D', 'a', 'c']
    >>> sorted(seq_str, key=str.lower)  # 小文字にした結果でソート
    ['a', 'B', 'c', 'D']
    
  • operator モジュール

    • key 引数に利用しやすい2つの関数 itemgetter() attrgetter() を提供
    • これらの関数は「呼び出し可能オブジェクト」を返すので、key 引数に渡せる

    itemgetter() ([index], [key] での取得に対応)

    >>> from operator import itemgetter
    >>> data = [(1, 40, 200), (3, 10, 100), (2, 20, 300), (1, 30, 300)]  # 3要素のタプルが4組
    >>> sorted(data)  # keyを指定しないでソート
    [(1, 30, 300), (1, 40, 200), (2, 20, 300), (3, 10, 100)]  # インデックス0から順に比較し同じなら次のインデックスで比較
    >>> sorted(data, key=itemgetter(2))  # インデックス2でソートし、それ以外はもとの順番を保つ
    [(3, 10, 100), (1, 40, 200), (2, 20, 300), (1, 30, 300)]
    >>> sorted(data, key=itemgetter(2, 0))  # インデックス2でソートし同じ場合は0でソート
    [(3, 10, 100), (1, 40, 200), (1, 30, 300), (2, 20, 300)]
    
    >>> from operator import itemgetter
    >>> dic = {'a': 2, 'c': 1, 'b': 3}
    >>> sorted(dic.items(), key=itemgetter(1))  # items()は2要素タプルとなるのでインデックス1を指定
    [('c', 1), ('a', 2), ('b', 3)]
    
    >>> from operator import itemgetter
    >>> users = [{"name": "terada", "age": 35},
    ...          {"name": "suzuki", "age": 25},
    ...          {"name": "sugita", "age": 30}]
    >>> sorted(users, key=itemgetter("age"))  # 辞書のageキーを使ってソートする
    [{'name': 'suzuki', 'age': 25}, {'name': 'sugita', 'age': 30}, {'name': 'terada', 'age': 35}]
    

    attrgetter() (「.」 (ドット) での取得に対応)

    >>> from operator import attrgetter
    >>> from datetime import date
    >>> date(1970, 11, 28).month  # month属性で月を取得できる
    11
    >>> date(1970, 11, 28).day  # day属性で日を取得できる
    28
    >>> dates = [date(1989, 1, 4),
    ...          date(1970, 11, 28),
    ...          date(1984, 3, 4)]  # ソート対象のdateオブジェクトのリストを定義
    >>> sorted(dates, key=attrgetter("month", "day"))  # "month"でソートし、次に"day"でソート
    [datetime.date(1989, 1, 4), datetime.date(1984, 3, 4), datetime.date(1970, 11, 28)]
    

    9.2 さまざまなコンテナー型を扱う collections

    • データの件数をカウントする Counter

      • 各要素が何回現れたが数えて保持する
        • 辞書の拡張であり、要素をキー、回数を値として保持する
      • class Counter([iterable-or-mapping])
        • iterable-or-mapping Counter オブジェクトの初期値を指定するマッピングオブジェクトまたはイテラブルオブジェクト
      >>> from collections import Counter
      >>> cnt = Counter("AAABBBCCCABCAAC")
      >>> cnt
      Counter({'A': 6, 'C': 5, 'B': 4})
      >>> cnt["A"]  # 辞書と同様の指定で、回数を取得
      6
      >>> cnt["D"]  # 通常の辞書と異なり、存在しないキー指定でも例外にならず 0 を返す
      0
      >>> "A" in cnt  # 存在チェックは可能
      True
      >>> "D" in cnt
      False
      >>> cnt["E"] = 0  # 直接代入
      >>> cnt
      Counter({'A': 6, 'C': 5, 'B': 4, 'E': 0})  # 0 も計数される
      >>> cnt["E"]
      0
      >>> "E" in cnt  # 回数 0 で存在する場合
      True
      
      メソッド名 解説 戻り値
      elements() キーを、値の数だけ繰り返すイテレーターを返す イテレーター
      most_common([n]) 値が大きい順に、キーと値のペアを返す
      n 指定の場合、最大 n 件の要素を返す
      list
      subtract(iterable-or-mapping) 要素からイテラブルまたはマッピングオブジェクトの値を減算する None
      update(iterable-or-mapping) (同上) 加算する None
      • メソッド使用例

        >>> cnt = Counter("AAABBBCCCABCAAC")
        >>> cnt
        Counter({'A': 6, 'C': 5, 'B': 4})
        >>> list(cnt.elements())
        ['A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'C']
        >>> cnt.most_common(2)
        [('A', 6), ('C', 5)]
        >>> cnt.subtract("CCCAA")
        >>> cnt
        Counter({'A': 4, 'B': 4, 'C': 2})
        >>> cnt.update("BBBDDDDD")
        >>> cnt
        Counter({'B': 7, 'D': 5, 'A': 4, 'C': 2})
        
      • 演算子 + - 各要素の値が計算される (値が 0 以下の要素は結果に含まれない)

      • 演算子 & | 各要素の値の最小、最大値 (片方にキーが無い場合は 0 と考える) (値が 0 以下の要素は結果に含まれない)

        >>> cnt1
        Counter({'A': 6, 'C': 5, 'B': 4})
        >>> cnt2
        Counter({'B': 4, 'A': 2})
        >>> cnt1 + cnt2
        Counter({'A': 8, 'B': 8, 'C': 5})
        >>> cnt1 - cnt2
        Counter({'C': 5, 'A': 4})
        
  • デフォルト値を持った辞書 defaultdict

    • 通常の辞書は存在しないキーを参照すると KeyError 例外が発生するが、defaultdict は例外発生ではなくデフォルト値を返す

    • class defaultdict([default_factory[, ...]])

      • default_factory 存在しないキーが参照されたときの値を返す、呼び出し可能オブジェクトを指定 (省略時は None で、通常の辞書と同じく例外送出)
      • また、default_factory には int list dict set が指定でき、それぞれ 0 または空のオブジェクトが返る defaultdict になる
      >>> d = {'spam':100}  # 通常の辞書を作成
      >>> d['ham']  # 存在しないないキーを指定するとKeyErrorが発生する
      Traceback (most recent call last):
        File "<input>", line 1, in <module>
      KeyError: 'ham'
      >>> from collections import defaultdict
      >>> def value():  # デフォルト値を返す関数を定義
      ...     return 'default-value'
      ...
      >>> dd = defaultdict(value, spam=100)  # デフォルトにvalue()関数を指定
      >>> dd  # 生成されたオブジェクトを確認
      defaultdict(<function value at 0x10748cee0>, {'spam': 100})
      >>> dd['ham']  # 存在しないキーを指定するとデフォルト値が返る
      'default-value'
      >>> dd['spam']
      100
      
    • default_factoryint list を使用する例

      >>> from collections import defaultdict
      >>> dd_int = defaultdict(int)   # デフォルト値は0
      >>> dd_int['spam']  # デフォルト値を確認
      0
      >>> dd_int['spam'] += 1  # 累算代入も使える
      >>> dd_int['spam']
      1
      >>> dd_list = defaultdict(list)  # デフォルト値は空のリスト
      >>> dd_list['spam']  # デフォルト値を確認
      []
      >>> dd_list['spam'].append('ham')
      >>> dd_list['spam'].append('egg')
      >>> dd_list['spam']
      ['ham', 'egg']
      
  • データの挿入順序を維持する辞書 OrderedDict

    • Python3.7 より前の辞書は、データの挿入順序が維持されなかった為、挿入順序維持の辞書として OrderedDict が利用された
    • Python3.7 から組み込みの辞書がでーたの挿入順を維持するようになっているので、新たな開発では使用しない
    メソッド名 解説 戻り値
    move_to_end(key, last=True) 指定したキーを末尾 (last=True) または先頭 (last=False) へ移動する None
    popitem(last=True) 末尾の要素 (last=True) または先頭の要素 (last=False) を取り出す 取り出したオブジェクト
    >>> from collections import OrderedDict
    >>> d = OrderedDict(one=1, two=2, three=3)
    >>> d
    OrderedDict({'one': 1, 'two': 2, 'three': 3})
    >>> d.move_to_end("one")
    >>> d
    OrderedDict({'two': 2, 'three': 3, 'one': 1})
    >>> d.move_to_end("three", last=False)
    >>> d
    OrderedDict({'three': 3, 'two': 2, 'one': 1})
    >>> d.popitem()
    ('one', 1)
    >>> d
    OrderedDict({'three': 3, 'two': 2})
    >>> d.popitem(last=False)
    ('three', 3)
    >>> d
    OrderedDict({'two': 2})
    
  • 名前付きフィールドを持つタプル namedtuple

    • タプルの各値に属性名を割り当て、インデックス以外に属性名から参照もできるタプル

    • 関数 namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)

      • typename 作成する型名を指定
      • field_names タプルの要素名を指定
        • 要素名シーケンス
        • 要素名をスペースかカンマで区切った文字列
      • rename True の場合、不正な要素名を自動的に位置名 (_1 など) に変換する
      • defaults デフォルト値のイテラブルを指定
      • module 名前付きタプルの __module__ 属性を指定した値に設定する
      • 戻り値 namedtuple オブジェクト
      >>> from collections import namedtuple
      >>> Pet = namedtuple('Pet', 'animal, name, age')  # Pet型を作成
      >>> seven = Pet('ferret', 'せぶん', 3)  # Pet型のインスタンスを作成
      >>> seven  # 「名前=値」の形式で確認できる
      Pet(animal='ferret', name='せぶん', age=3)
      >>> michiko = Pet('cat', 'ミチコ', 1)  # 別のインスタンスを作成
      >>> michiko
      Pet(animal='cat', name='ミチコ', age=1)
      >>> seven.age  # 属性名で値を取得
      3
      >>> seven[1]  # インデックスでもアクセスできる
      'せぶん'
      >>> animal, name, age = michiko  # アンパック代入も可能
      >>> animal
      'cat'
      

9.3 二分法アルゴリズムを利用する bisect

  • 二分法アルゴリズムで挿入する位置を返す

    • bisect_left(a, x, lo=0, hi=len(a))

    • bisect_right(a, x, lo=0, hi=len(a))

    • bisect(a, x, lo=0, hi=len(a))

      • a ソート済みのシーケンス
      • x 挿入位置を検索する値
      • lo 検索開始位置
      • hi 検索終了位置
      • 戻り値 挿入位置のインデックス
        • ソート済みシーケンス ax を挿入する位置のインデックス (ax が含まれない場合、全関数は同じ結果)
        • ax が含まれる場合
          • bisect_left() は、最初の x の位置インデックスを返す
          • bisect_right() bisect() は、最後の x の次の位置インデックスを返す
      >>> import bisect
      >>> seq = [0, 1, 2, 2, 3, 5]  # 昇順にソートしたリスト
      >>> bisect.bisect_left(seq, 4)  # 4の挿入インデックスは5
      5
      >>> bisect.bisect_right(seq, 4)  # bisect_rightでも同じ
      5
      >>> bisect.bisect_left(seq, 2)  # 最初の2の要素のインデックスを返す
      2
      >>> bisect.bisect_right(seq, 2)  # 最後の2の要素の次のインデックスを返す
      4
      
  • ソート済みのリストに要素を挿入する

    • insort_left(a, x, lo=0, hi=len(a))
    • insort_right(a, x, lo=0, hi=len(a))
    • insort(a, x, lo=0, hi=len(a))
      • a ソート済みの リスト (※ bisect() 等と異なり、指定できるのはリストのみ)
      • (残り引数略:bisect() 等と同じ)
      • 戻り値 None
    • 第1引数のリストを変更する、破壊的操作となる

9.4 列挙型による定数の定義を行う enum

  • 定数値を定義する

    • 列挙型は enum.Enum の派生クラスに定義する

      import enum
      
      class Example(enum.Enum):
          名前1 = 値1
          名前2 = 値2
          名前3 = 値3
      
      >>> import enum
      >>> class Nengo(enum.Enum):
      ...     SHOWA = enum.auto()
      ...     HEISEI = enum.auto()
      ...     REIWA = enum.auto()
      ...
      >>> Nengo.SHOWA     # 属性で定数取得
      <Nengo.SHOWA: 1>
      >>> Nengo["SHOWA"]  # キーで定数取得
      <Nengo.SHOWA: 1>
      >>> Nengo(2)        # 値から定数取得
      <Nengo.HEISEI: 2>
      >>> Nengo.SHOWA.name   # 定数の名前
      'SHOWA'
      >>> Nengo.SHOWA.value  # 定数の値
      1
      >>> for ng in Nengo:  # 列挙型は定数を定義順に返すイテレーターを返す
      ...     print(f"{ng.name} : {ng.value}")
      ...
      SHOWA : 1
      HEISEI : 2
      REIWA : 3
      
    • 定数同士の比較

      >>> import enum
      >>> class Spam(enum.Enum):
      ...     HAM = 1
      ...     EGG = 2
      ...     BACON = 2
      ...
      >>> isinstance(Spam.HAM, Spam)  # HAM、EGG、BACONはSpam型のインスタンス
      True
      >>> Spam.HAM == Spam.HAM  # 同じ値同士の比較
      True
      >>> Spam.HAM == Spam.EGG  # 異なる値との比較
      False
      >>> Spam.EGG == Spam.BACON  # 別の名前でも値が同じなら等しい
      True
      >>> class OtherSpam(enum.Enum):
      ...     HAM = 1
      ...     EGG = 2
      ...     BACON = 2
      ...
      >>> Spam.HAM == OtherSpam.HAM  # 異なる列挙型の同じ値(=1)同士の比較
      False
      >>> Spam.HAM == 1  # 整数値との比較
      False
      
  • enum は関数やメソッドの引数に使用することで「引数が特定のパターンしか受け付けない」仕様を記述できる

    • ただし、動的型付けにより期待以外の値が渡されることは防げないので、mypy などの静的型チェックを行うことで制限できる
  • 列挙型の定数参照は、文字列を使用した Nengo["SHOWA"] の形式で可能だが、この場合文字列として定義外の定数名を指定してしまうことがあり、その場合は KeyError が送出される

9.5 データを読みやすい形で出力する pprint

  • オブジェクトを整形して出力する pprint

    • pprint(object, stream=None, indent=1, width=80, depth=None, compact=False, sort_dicts=True)

      • object 出力するオブジェクト
      • stream 出力先のファイルオブジェクト (None なら sys.stdout)
      • indent ネストしたオブジェクト出力の際のインデント数
      • width 出力幅
      • depth ネストしたオブジェクト出力の際の最大レベル数 (None なら全レベル)
      • compact 出力されるシーケンスの整形方法の指定
        • True : 各行に width の幅に収まるだけの要素を出力
        • False : 1 行に 1 要素を出力
      • sort_dicts 出力される辞書の整形方法の指定
        • True : キーでソートして出力
        • False : 挿入順に出力
      • 戻り値 None
      >>> import pprint
      >>> import sys
      >>> sys.implementation  # 1行につながっていて読みにくい
      namespace(name='cpython', cache_tag='cpython-39', version=sys.version_info(major=3, minor=9, micro=5, releaselevel='final', serial=0), hexversion=50922992, _multiarch='darwin')
      >>> pprint.pprint(sys.implementation)
      namespace(name='cpython',
                cache_tag='cpython-39',
                version=sys.version_info(major=3, minor=9, micro=5, releaselevel='final', serial=0),
                hexversion=50922992,
                _multiarch='darwin')
      
  • オブジェクトを整形した文字列を取得する pformat

    • pformat(object, indent=1, width=80, depth=None, compact=False, sort_dicts=True)

      • (引数略 : stream が無い以外は pprint() と同じ)
      • 戻り値 整形された文字列
      >>> import pprint
      >>> formatted_implementation = pprint.pformat(sys.implementation)
      >>> print(formatted_implementation)
      namespace(name='cpython',
                cache_tag='cpython-39',
                version=sys.version_info(major=3, minor=9, micro=5, releaselevel='final', serial=0),
                hexversion=50922992,
                _multiarch='darwin')
      
  • ログ出力関連でよく使用される

  • pprint は pdb デバッガーの pp コマンドの内部でも使用されている (17.1 参照)

9.6 イテレーターの組み合わせで処理を組み立てる itertools

  • イテラブルオブジェクトを連結する

    • chain(*iterables)

      • iterables 複数のイテラブルオブジェクト
      • 戻り値 イテレーター
      >>> import itertools
      >>> lt = [0, 5, 2]
      >>> it = itertools.chain(lt, "ABC", range(3))
      >>> for elem in it:
      ...     elem
      ...
      0
      5
      2
      'A'
      'B'
      'C'
      0
      1
      2
      
  • 連続する値をまとめる

    • groupby(iterable, key=Noen)

      • iterable イテラブルオブジェクト
      • key 比較対象値を取得する関数を指定 (省略 or None の場合、要素をそのまま比較)
      • 戻り値 グループ化されたイテレーター
        • 「長さ2のタプル」のイテレーター
        • 各タプルの第1要素は iterable の単一要素、第2要素は連続した等しい値のオブジェクトを返すイテレーター
      >>> import itertools
      >>> for value, group in itertools.groupby('aaabbcdddaabb'):  # 同じ文字ごとにグループ化する
      ...     print(f'{value}: {list(group)}')  # 各要素とイテレーターをリストに変換して確認
      ...
      a: ['a', 'a', 'a']
      b: ['b', 'b']
      c: ['c']
      d: ['d', 'd', 'd']
      a: ['a', 'a']
      b: ['b', 'b']
      
    • key を指定した例

      >>> import itertools
      >>> def is_odd(num):
      ...     return num % 2 == 1  # 奇数ならTrueを返す
      ...
      >>> numbers = [10, 20, 31, 11, 3, 4]
      >>> for value, group in itertools.groupby(numbers, is_odd):  # is_odd()関数の結果でグループ化
      ...     print(f'{value}: {list(group)}')
      ...
      False: [10, 20]
      True: [31, 11, 3]
      False: [4]
      
  • イテレーターから範囲を指定して値を取得する

    • リスト等のスライスと同様の部分取得を提供

    • islice(iterable, stop)

    • islice(iterable, start, stop[, step])

      • iterable イテレーターオブジェクト
      • stop 値読み取りの終了位置 (None の場合は最後まで取得)
      • start 値読み取りの開始位置 (未指定 or None の場合は最初から取得)
      • step 値を読み取る際の増分 (デフォルトは 1)
      >>> import itertools
      >>> li = list(range(10))
      >>> li
      [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      >>> li
      >>> islice_object = itertools.islice(li, 5)  # リストの最初の5要素を返す
      >>> islice_object
      <itertools.islice object at 0x1089de8b0>
      >>> list(islice_object)  # リストに変換して確認する
      [0, 1, 2, 3, 4]
      
  • 複数のイテラブルオブジェクトの要素からタプルを作成する

    • zip(*iterables) (組み込み関数)

      • iterables イテラブルオブジェクト
      • 戻り値 zipイテレーター
        • 指定された複数のイテラブルオブジェクから、各第 n 要素を並べたタプルを返すイテレーター
        • イテラブルオブジェクトの長さが異なる場合は、最短のものに揃えて終わる
        • Python3.10 以降では strict 引数が追加され、True 指定すると、長さが異なるイテラブルを指定した際に ValueError 送出となる
      >>> it1 = (1, 2, 3, 4, 5)  # 長さが5のため、後ろ2つは切り捨てられる
      >>> it2 = ['abc', 'ABC', '123']  # 長さが3
      >>> for v in zip(it1, it2):  # 2つのイテラブルオブジェクトを指定
      ...    print(v)
      ...
      (1, 'abc')
      (2, 'ABC')
      (3, '123')
      
    • zip_longest(*iterables, fillvalue=None) (itertools モジュール)

      • iterables イテラブルオブジェクト
      • fillvalue イテラブルオブジェクの要素が存在しない (足りない) 場合に使用する値
      • 戻り値 zip_longest イテレーター
        • 指定された複数のイテラブルオブジェクから、各第 n 要素を並べたタプルを返すイテレーター
        • イテラブルオブジェクトの長さが異なる場合は、最長のものに揃えられ 、短いイテラブルオブジェクトの要素として fillvalue の値が使用される
      >>> import itertools
      >>> for v in itertools.zip_longest('abcde', '123', 'あいうえ', fillvalue='-'):
      ...     print(v)
      ...
      ('a', '1', '')
      ('b', '2', '')
      ('c', '3', '')
      ('d', '-', '')
      ('e', '-', '-')
      
  • データを組み合わせたイテレーターを取得する

    関数 解説 文字列 ABC 長さ 2 の場合の結果
    product(*iterables, repeat=1) デカルト積 AA AB AC BA BB BC CA CB CC
    permutations(iterable, r=None) 順列 AB AC BA BC CA CB
    combinations(iterable, r) 組み合わせ AB AC BC
    combinations_with_replacement(iterable, r) 組み合わせ (同要素の繰り返しを含む) AA AB AC BB BC CC

9.7 ミュータブルなオブジェクトをコピーする copy

  • 浅いコピーを行う

    • copy() 関数

    • 1 階層のみのコピーを行う

    • 2 階層目以降は参照がコピーされる

      >>> import copy
      >>> values = [[0, 1], [2, 3], [4, 5]]  # もとのオブジェクトが2つの階層を持つ
      >>> val_cp = copy.copy(values)
      >>> val_cp.append([6, 7])  # コピー先のオブジェクトに値を追加
      >>> val_cp
      [[0, 1], [2, 3], [4, 5], [6, 7]]  # コピー先のオブジェクトのみに値が追加される
      >>> values
      [[0, 1], [2, 3], [4, 5]]  # コピー元オブジェクトは変更されていない
      >>> val_cp[1][0] = 8  # 子オブジェクト(2階層目)の値を変更してみる
      >>> val_cp
      [[0, 1], [8, 3], [4, 5], [6, 7]]  # コピー先オブジェクトが変更されている
      >>> values
      [[0, 1], [8, 3], [4, 5]]  # コピー元のオブジェクトも変更されている
      
  • 深いコピーを行う

    • deepcopy() 関数

    • 子オブジェクトも再帰的にコピーする

      >>> import copy
      >>> class Author:  # クラスを作成
      ...     def __init__(self, name, age):
      ...         self.name = name  # 名前
      ...         self.age = age  # 年齢
      ...
      >>> author1 = Author('kadowaki', 25)  # インスタンス1
      >>> author2 = Author('terada', 20)  # インスタンス2
      >>> author3 = copy.deepcopy(author1)  # deepcopy()関数でインスタンスをコピー
      >>> author3.name = 'takanory'
      >>> print(author1.name, author1.age)
      kadowaki 25
      >>> print(author2.name, author2.age)
      terada 20
      >>> print(author3.name, author3.age)
      takanory 25
      
  • copy モジュールを使用しない浅いコピー

    • リストに対して全体指定となるスライスを使用

      >>> values = [0, 1, 2, 3, 4, 5]
      >>> val_cp = values[:]  # スライスを使用してリスト全体を指定
      >>> val_cp
      [0, 1, 2, 3, 4, 5]
      >>> id(values)
      140016803582400
      >>> id(val_cp)
      140016804734336
      
    • 組み込み関数 list() dict() set() を使用

      >>> values_list = [0, 1, 2, 3, 4, 5]  # リスト型の元データ
      >>> values_dict = {'key1': 'value1', 'key2': 'value2'}  # 辞書型の元データ
      >>> values_set = {1, 2, 3, 4, 5}  # 集合型の元データ
      >>> val_list_cp = list(values_list)  # list()関数を使用したコピー
      >>> val_dict_cp = dict(values_dict)  # dict()関数を使用したコピー
      >>> val_set_cp = set(values_set)  # set()関数を使用したコピー
      

Tatsuya ISHIGAKI さんが5ヶ月前に更新 · 1件の履歴