collections --- コンテナデータ型

ソースコード: Lib/collections/__init__.py


このモジュールは、汎用の Python 組み込みコンテナ dict, list, set, および tuple に代わる、特殊なコンテナデータ型を実装しています。

namedtuple()

名前付きフィールドを持つタプルのサブクラスを作成するファクトリ関数

deque

両端における append や pop を高速に行えるリスト風のコンテナ

ChainMap

複数のマッピングの一つのビューを作成する辞書風のクラス

Counter

ハッシュ可能 なオブジェクトを数え上げる辞書のサブクラス

OrderedDict

項目が追加された順序を記憶する辞書のサブクラス

defaultdict

ファクトリ関数を呼び出して存在しない値を供給する辞書のサブクラス

UserDict

辞書のサブクラス化を簡単にする辞書オブジェクトのラッパ

UserList

リストのサブクラス化を簡単にするリストオブジェクトのラッパ

UserString

文字列のサブクラス化を簡単にする文字列オブジェクトのラッパ

ChainMap オブジェクト

Added in version 3.3.

ChainMap クラスは、複数のマッピングを素早く連結し、一つの単位として扱うために提供されています。これはたいてい、新しい辞書を作成して update() を繰り返すよりも早いです。

このクラスはネストされたスコープをシミュレートするのに使え、テンプレート化に便利です。

class collections.ChainMap(*maps)

ChainMap は、複数の辞書やその他のマッピングをまとめて、一つの、更新可能なビューを作成します。 maps が指定されないなら、一つの空辞書が与えられますから、新しいチェーンは必ず一つ以上のマッピングをもちます。

根底のマッピングはリストに保存されます。このリストはパブリックで、 maps 属性を使ってアクセスや更新できます。それ以外に状態はありません。

探索は、根底のマッピングをキーが見つかるまで引き続き探します。対して、書き込み、更新、削除は、最初のマッピングのみ操作します。

ChainMap は、根底のマッピングを参照によって組み込みます。ですから、根底のマッピングの一つが更新されると、その変更は ChainMap に反映されます。

通常の辞書のメソッドすべてがサポートされています。さらに、maps 属性、新しいサブコンテキストを作成するメソッド、最初のマッピング以外のすべてにアクセスするためのプロパティがあります:

maps

ユーザーが更新できるマッピングのリストです。 マッピングは最初に検索されるものから最後に検索されるものの順に並んでいます。 保存される状態はこのリストだけであり、リストを変更すると検索対象のマッピングを変更できます。 リストには常に少なくとも一つのマッピングが含まれていなければなりません。

new_child(m=None, **kwargs)

新しいマッピングに現在のインスタンスが持つ全てのマッピングを追加したものを持つ新しい ChainMap インスタンスを返します。 m が指定された場合、新しいマッピングのリストの先頭部分になります; 指定されない場合は空の辞書が使われます。すなわち d.new_child() は ChainMap({}, *d.maps) と等価になります。キーワード引数が指定された場合、それらによって指定されたマッピングまたは空の辞書が更新されます。このメソッドは、元のマッピングに変更を加えることなく値を更新できるサブコンテキストを生成するのに使われます。

バージョン 3.4 で変更: オプションの m 引数が追加されました。

バージョン 3.10 で変更: キーワード引数のサポートが追加されました。

parents

現在のインスタンスの最初のマッピング以外のすべてのマッピングを含む新しい ChainMap を返すプロパティです。これは最初のマッピングを検索から飛ばすのに便利です。使用例は nonlocal キーワードを ネストされたスコープ に使う例と似ています。この使用例はまた、組み込み super() 関数にも似ています。 d.parents への参照は ChainMap(*d.maps[1:]) と等価です。

ChainMap の反復順序は、マッピングを最後から最初へスキャンして決定されることに注意してください。

>>> baseline = {'music': 'bach', 'art': 'rembrandt'}
>>> adjustments = {'art': 'van gogh', 'opera': 'carmen'}
>>> list(ChainMap(adjustments, baseline))
['music', 'art', 'opera']

これは、末尾のマッピングオブジェクトから始めた一連の dict.update() の呼び出しと同じ順序になります。

>>> combined = baseline.copy()
>>> combined.update(adjustments)
>>> list(combined)
['music', 'art', 'opera']

バージョン 3.9 で変更: PEP 584 で規定されている | 演算子と |= 演算子のサポートを追加しました。

参考

ChainMap の例とレシピ

この節では、チェーンされたマッピングを扱う様々な手法を示します。

Python の内部探索チェーンをシミュレートする例:

import builtins
pylookup = ChainMap(locals(), globals(), vars(builtins))

ユーザ指定のコマンドライン引数、環境変数、デフォルト値、の順に優先させる例:

import os, argparse

defaults = {'color': 'red', 'user': 'guest'}

parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = {k: v for k, v in vars(namespace).items() if v is not None}

combined = ChainMap(command_line_args, os.environ, defaults)
print(combined['color'])
print(combined['user'])

ChainMap を使ってネストされたコンテキストをシミュレートするパターンの例:

c = ChainMap()        # Create root context
d = c.new_child()     # Create nested child context
e = c.new_child()     # Child of c, independent from d
e.maps[0]             # Current context dictionary -- like Python's locals()
e.maps[-1]            # Root context -- like Python's globals()
e.parents             # Enclosing context chain -- like Python's nonlocals

d['x'] = 1            # Set value in current context
d['x']                # Get first key in the chain of contexts
del d['x']            # Delete from current context
list(d)               # All nested values
k in d                # Check all nested values
len(d)                # Number of nested values
d.items()             # All nested items
dict(d)               # Flatten into a regular dictionary

ChainMap クラスは、探索はチェーン全体に対して行いますが、更新 (書き込みと削除) は最初のマッピングに対してのみ行います。しかし、深い書き込みと削除を望むなら、チェーンの深いところで見つかったキーを更新するサブクラスを簡単に作れます:

class DeepChainMap(ChainMap):
    '内側のスコープを直接更新できる ChainMap の変種'

    def __setitem__(self, key, value):
        for mapping in self.maps:
            if key in mapping:
                mapping[key] = value
                return
        self.maps[0][key] = value

    def __delitem__(self, key):
        for mapping in self.maps:
            if key in mapping:
                del mapping[key]
                return
        raise KeyError(key)

>>> d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})
>>> d['lion'] = 'orange'         # 2 階層下の既存のキーを更新
>>> d['snake'] = 'red'           # 新しいキーは最上位の辞書に追加
>>> del d['elephant']            # 1 階層下の既存のキーを削除
>>> d                            # 結果を表示
DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})

Counter オブジェクト

便利で迅速な検数をサポートするカウンタツールが提供されています。例えば:

>>> # リスト内の単語の出現回数を数える
>>> cnt = Counter()
>>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
...     cnt[word] += 1
...
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})

>>> # Hamlet で最も頻出する単語を 10 個見つける
>>> import re
>>> words = re.findall(r'\w+', open('hamlet.txt').read().lower())
>>> Counter(words).most_common(10)
[('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),
 ('you', 554),  ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]
class collections.Counter(**kwargs)
class collections.Counter(iterable, /, **kwargs)
class collections.Counter(mapping, /, **kwargs)

Counter は ハッシュ可能 なオブジェクトをカウントする dict のサブクラスです。これは、要素を辞書のキーとして保存し、そのカウントを辞書の値として保存するコレクションです。カウントは、0 や負のカウントを含む整数値をとれます。 Counter クラスは、他の言語のバッグや多重集合のようなものです。

要素は、 iterable から数え上げられたり、他の mapping (やカウンタ) から初期化されます:

>>> c = Counter()                           # a new, empty counter
>>> c = Counter('gallahad')                 # a new counter from an iterable
>>> c = Counter({'red': 4, 'blue': 2})      # a new counter from a mapping
>>> c = Counter(cats=4, dogs=8)             # a new counter from keyword args

カウンタオブジェクトは辞書のインターフェースを持ちますが、存在しない要素に対して KeyError を送出する代わりに 0 を返すという違いがあります:

>>> c = Counter(['eggs', 'ham'])
>>> c['bacon']                              # count of a missing element is zero
0

カウントを 0 に設定しても、要素はカウンタから取り除かれません。完全に取り除くには、 del を使ってください:

>>> c['sausage'] = 0                        # counter entry with a zero count
>>> del c['sausage']                        # del actually removes the entry

Added in version 3.1.

バージョン 3.7 で変更: Counter は dict のサブクラスとして要素の挿入順を維持する機能を継承しました。 Counter オブジェクトに対する数学演算も順序を維持します。結果の順序はまず左の被演算子における要素の出現順に従い、その後右の被演算子において要素が出現する順序になります。

カウンタオブジェクトは全ての辞書で利用できるメソッドに加えて、以下に示す追加のメソッドをサポートしています。

elements()

それぞれの要素を、そのカウント分の回数だけ繰り返すイテレータを返します。要素は挿入した順番で返されます。ある要素のカウントが 1 未満なら、 elements() はそれを無視します。

>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> sorted(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']
most_common(n=None)

出現回数が多い順に n 個の要素とそれぞれのカウントを並べたリストを返します。 n が省略されるか None であれば、 most_common() はカウンタの すべての 要素を返します。 等しいカウントの要素は挿入順に並べられます:

>>> Counter('abracadabra').most_common(3)
[('a', 5), ('b', 2), ('r', 2)]
subtract(**kwargs)
subtract(iterable, /, **kwargs)
subtract(mapping, /, **kwargs)

要素から iterable の要素または mapping の要素が引かれます。 dict.update() に似ていますが、カウントを置き換えるのではなく引きます。入力も出力も、 0 や負になりえます。

>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> d = Counter(a=1, b=2, c=3, d=4)
>>> c.subtract(d)
>>> c
Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})

Added in version 3.2.

total()

カウントの合計を計算します。

>>> c = Counter(a=10, b=5, c=0)
>>> c.total()
15

Added in version 3.10.

通常の辞書のメソッドは Counter オブジェクトでも利用できますが、次の二つはカウンタでは動作が異なります:

fromkeys(iterable)

このクラスメソッドは Counter オブジェクトには実装されていません。

update(**kwargs)
update(iterable, /, **kwargs)
update(mapping, /, **kwargs)

要素が iterable からカウントされるか、別の mapping (やカウンタ) が追加されます。 dict.update() に似ていますが、カウントを置き換えるのではなく追加します。また、 iterable には (key, value) 対のシーケンスではなく、要素のシーケンスが求められます。

カウンタオブジェクトは等価、部分集合、上位集合のための次の拡張比較 (rich comparison) 演算子をサポートします: ==, !=, <, <=, >, >=。これらの比較は、存在しない要素をカウントがゼロであるとみなします。すなわち、 Counter(a=1) == Counter(a=1, b=0) は真を返します。

バージョン 3.10 で変更: 拡張比較 (rich comparison) 演算が追加されました。

バージョン 3.10 で変更: 等価比較において、存在しない要素はカウントがゼロであるとみなされるようになりました。かつては Counter(a=3) と Counter(a=3, b=0) は異なるとみなされていました。

Counter オブジェクトを使ったよくあるパターン:

c.total()                       # すべてのカウントの合計
c.clear()                       # すべてのカウントをリセット
list(c)                         # 重複しない要素のリスト
set(c)                          # 集合に変換
dict(c)                         # 通常の辞書に変換
c.items()                       # (elem, cnt) のペアにアクセス
Counter(dict(list_of_pairs))    # (elem, cnt) のペアのリストから変換
c.most_common()[:-n-1:-1]       # 出現回数が少ない方から n 個の要素
+c                              # 0 と負のカウントを削除

Counter オブジェクトを組み合わせて多重集合 (カウントが 0 より大きいカウンタ) を作るために、いくつかの数学演算が用意されています。 加算と減算は、対応する要素のカウントを加算または減算してカウンタを組み合わせます。 共通部分と和集合は、対応するカウントの最小値と最大値を返します。 対称差は、対応するカウントの最大値と最小値の差を返します。 等価性と包含関係の比較では、対応するカウントを比較します。 各演算には符号付きのカウントを入力できますが、出力からはカウントが 0 以下の結果が除外されます。

>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d                       # 二つのカウンタを加算:  c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d                       # 減算 (正のカウントのみ残す)
Counter({'a': 2})
>>> c & d                       # 共通部分:  min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d                       # 和集合:  max(c[x], d[x])
Counter({'a': 3, 'b': 2})
>>> c ^ d                       # max(c[x], d[x]) - min(c[x], d[x])
Counter({'a': 2, 'b': 1})
>>> c == d                      # 等価性:  c[x] == d[x]
False
>>> c <= d                      # 包含関係:  c[x] <= d[x]
False

単項加算および減算は、空カウンタの加算や空カウンタからの減算へのショートカットです。

>>> c = Counter(a=2, b=-4)
>>> +c
Counter({'a': 2})
>>> -c
Counter({'b': 4})

Added in version 3.3: 単項加算、単項減算、in-place の多重集合操作のサポートが追加されました。

Added in version 3.15: 多重集合の対称差演算 c ^ d のサポートが追加されました。

注釈

カウンタはもともと、推移するカウントを正の整数で表すために設計されました。しかし、他の型や負の値を必要とするユースケースを不必要に排除することがないように配慮されています。このようなユースケースの助けになるように、この節で最低限の範囲と型の制限について記述します。

  • Counter クラス自体は辞書のサブクラスで、キーと値に制限はありません。値はカウントを表す数であることを意図していますが、値フィールドに任意のものを保存 できます 。

  • most_common() メソッドが要求するのは、値が順序付け可能なことだけです。

  • c[key] += 1 のようなインプレース演算では、値の型に必要なのは 足し算と引き算ができることだけです。よって分数、浮動小数点数、 小数も使え、負の値がサポートされています。これと同じことが、 負や 0 の値を入力と出力に許す update() と subtract() メソッド にも言えます。

  • 多重集合メソッドは正の値を扱うユースケースに対してのみ設計されています。入力は負や 0 に出来ますが、正の値の出力のみが生成されます。型の制限はありませんが、値の型は足し算、引き算、比較をサポートしている必要があります。

  • elements() メソッドは整数のカウントを要求します。これは 0 と負のカウントを無視します。

参考

  • Smalltalk の Bag class 。

  • Wikipedia の Multisets の項目。

  • C++ multisets の例を交えたチュートリアル。

  • 数学的な多重集合の演算とそのユースケースは、 Knuth, Donald. The Art of Computer Programming Volume II, Section 4.6.3, Exercise 19 を参照してください。

  • 与えられた要素の集まりからなる与えられた大きさの相違なる多重集合をすべて数え上げるには、 itertools.combinations_with_replacement() を参照してください:

    map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC
    

deque オブジェクト

class collections.deque([iterable[, maxlen]])

iterable で与えられるデータから、新しい deque オブジェクトを (append() をつかって) 左から右に初期化して返します。 iterable が指定されない場合、新しい deque オブジェクトは空になります。

Deque とは、スタックとキューを一般化したものです (この名前は「デック」と発音され、これは「double-ended queue」の省略形です)。Deque はどちらの側からも append と pop が可能で、スレッドセーフでメモリ効率がよく、どちらの方向からもおよそ O(1) のパフォーマンスで実行できます。

list オブジェクトでも同様の操作を実現できますが、これは高速な固定長の操作に特化されており、基礎のデータ表現形式のサイズと位置を両方変えるような pop(0) や insert(0, v) などの操作ではメモリ移動のために O(n) のコストを必要とします。

maxlen が指定されなかったり None だった場合、 deque は任意のサイズまで大きくなります。 そうでない場合、 deque のサイズは指定された最大長に制限されます。 長さが制限された deque がいっぱいになると、新しい要素を追加するときに追加した要素数分だけ追加したのと反対側から要素が捨てられます。 長さが制限された deque は Unix における tail フィルタと似た機能を提供します。 トランザクションの tracking や最近使った要素だけを残したいデータプール (pool of data) などにも便利です。

deque は、要素の型をパラメータとする ジェネリック です。

Deque オブジェクトは以下のようなメソッドをサポートしています:

append(item, /)

item を deque の右側に追加します。

appendleft(item, /)

item を deque の左側に追加します。

clear()

deque からすべての要素を削除し、長さを 0 にします。

copy()

deque の浅いコピーを作成します。

Added in version 3.5.

count(value, /)

deque 内で value と等しい要素の数を数えます。

Added in version 3.2.

extend(iterable, /)

イテラブルな引数 iterable から得られる要素を deque の右側に追加し拡張します。

extendleft(iterable, /)

イテラブルな引数 iterable から得られる要素を deque の左側に追加し拡張します。注意: 左から追加した結果は、イテラブルな引数の順序とは逆になります。

index(value[, start[, stop]])

deque 内の value の位置 (インデックス start 以上、インデックス stop 未満) を返します。 最初に一致した位置を返し、見つからない場合は ValueError を送出します。

Added in version 3.5.

insert(index, value, /)

deque の位置 index に value を挿入します。

挿入によって、長さに制限のある deque の長さが maxlen を超える場合、IndexError が発生します。

Added in version 3.5.

pop()

deque の右側から要素をひとつ削除し、その要素を返します。要素がひとつも存在しない場合は IndexError を発生させます。

popleft()

deque の左側から要素をひとつ削除し、その要素を返します。要素がひとつも存在しない場合は IndexError を発生させます。

remove(value, /)

value の最初に現れるものを削除します。要素が見付からないない場合は ValueError を送出します。

reverse()

deque の要素をインプレースに反転し、None を返します。

Added in version 3.2.

rotate(n=1, /)

deque の要素を全体で n ステップだけ右にローテートします。n が負の値の場合は、左にローテートします。

deque が空でないときは、 deque をひとつ右にローテートすることは d.appendleft(d.pop()) と同じで、 deque をひとつ左にローテートすることは d.append(d.popleft()) と同じです。

deque オブジェクトは読み出し専用属性も 1 つ提供しています:

maxlen

deque の最大長で、制限されていなければ None です。

Added in version 3.1.

上記に加え、 deque はイテレーション, pickle 化, len(d), reversed(d), copy.copy(d), copy.deepcopy(d), in 演算子による包含の検査, d[0] のような添字による参照をサポートしています。添字によるアクセスは、両端の要素では O(1) ですが、中央部分の要素では O(n) と遅くなります。高速なランダムアクセスのためには、代わりにリストを使ってください。

バージョン 3.5 から deque は __add__(), __mul__(), __imul__() をサポートしました。

例:

>>> from collections import deque
>>> d = deque('ghi')                 # 3 要素の deque を新しく作成
>>> for elem in d:                   # deque の要素を反復処理
...     print(elem.upper())
G
H
I

>>> d.append('j')                    # 新しい要素を右側に追加
>>> d.appendleft('f')                # 新しい要素を左側に追加
>>> d                                # deque の表現を表示
deque(['f', 'g', 'h', 'i', 'j'])

>>> d.pop()                          # 右端の要素を返して削除
'j'
>>> d.popleft()                      # 左端の要素を返して削除
'f'
>>> list(d)                          # deque の内容をリストにする
['g', 'h', 'i']
>>> d[0]                             # 左端の要素を見る
'g'
>>> d[-1]                            # 右端の要素を見る
'i'

>>> list(reversed(d))                # deque の内容を逆順のリストにする
['i', 'h', 'g']
>>> 'h' in d                         # deque を検索
True
>>> d.extend('jkl')                  # 複数の要素を一度に追加
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1)                      # 右にローテート
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1)                     # 左にローテート
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])

>>> deque(reversed(d))               # 逆順の deque を新しく作成
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear()                        # deque を空にする
>>> d.pop()                          # 空の deque からは取り出せない
Traceback (most recent call last):
    File "<pyshell#6>", line 1, in -toplevel-
        d.pop()
IndexError: pop from an empty deque

>>> d.extendleft('abc')              # extendleft() は入力の順序を反転する
>>> d
deque(['c', 'b', 'a'])

deque のレシピ

この節では deque を使った様々なアプローチを紹介します。

長さが制限された deque は Unix における tail フィルタに相当する機能を提供します:

def tail(filename, n=10):
    'ファイルの末尾 n 行を返す'
    with open(filename) as f:
        return deque(f, n)

deque を使用する別のアプローチは、右に要素を追加し左から要素を取り出すことで最近追加した要素のシーケンスを保持することです:

def moving_average(iterable, n=3):
    # moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
    # https://en.wikipedia.org/wiki/Moving_average
    it = iter(iterable)
    d = deque(itertools.islice(it, n-1))
    d.appendleft(0)
    s = sum(d)
    for elem in it:
        s += elem - d.popleft()
        d.append(elem)
        yield s / n

入力イテレータを deque に格納すると、ラウンドロビンスケジューラ を実装できます。 位置 0 にあるアクティブなイテレータから値を yield します。 そのイテレータが 使い果たされた 場合は popleft() で削除でき、それ以外の場合は rotate() メソッドで末尾に戻せます。

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    iterators = deque(map(iter, iterables))
    while iterators:
        try:
            while True:
                yield next(iterators[0])
                iterators.rotate(-1)
        except StopIteration:
            # 使い果たされたイテレータを削除
            iterators.popleft()

rotate() メソッドを使うと deque のスライスや削除を実装できます。 例えば、del d[n] を純粋な Python で実装するには、rotate() メソッドで削除対象の要素を取り出せる位置に移動します。

def delete_nth(d, n):
    d.rotate(-n)
    d.popleft()
    d.rotate(n)

deque のスライスの実装でも、同様のアプローチを使います。まず対象となる要素を rotate() によって deque の左端まで移動させてから、 popleft() で古い要素を削除します。そして、 extend() で新しい要素を追加したのち、循環を逆にします。このアプローチをやや変えたものとして、Forth スタイルのスタック操作、つまり dup, drop, swap, over, pick, rot, および roll を実装するのも簡単です。

defaultdict オブジェクト

class collections.defaultdict(default_factory=None, /, **kwargs)
class collections.defaultdict(default_factory, mapping, /, **kwargs)
class collections.defaultdict(default_factory, iterable, /, **kwargs)

新しい辞書に似たオブジェクトを返します。 defaultdict は組み込みの dict クラスのサブクラスです。これはメソッドをひとつオーバーライドし、書き込み可能なインスタンス変数をひとつ追加しています。それ以外の機能は dict クラスと同じですので、ここでは説明しません。

1つ目の引数は default_factory 属性の初期値です。デフォルトは None です。残りの引数はキーワード引数も含め、 dict のコンストラクタに与えられた場合と同様に扱われます。

defaultdict は、辞書のキーと値の型をそれぞれ表す二つの型をパラメータとする ジェネリック です。

defaultdict オブジェクトは標準の dict に加えて、以下のメソッドを実装しています:

__missing__(key, /)

もし default_factory 属性が None であれば、このメソッドは KeyError 例外を、 key を引数として発生させます。

default_factory が None でない場合は、それを引数なしで呼び出して key のデフォルト値を取得します。 この値を辞書に key の値として登録し、返します。

もし default_factory の呼出が例外を発生させた場合には、変更せずそのまま例外を投げます。

このメソッドは dict クラスの __getitem__() メソッドで、キーが存在しなかった場合によびだされます。値を返すか例外を発生させるのどちらにしても、 __getitem__() からもそのまま値が返るか例外が発生します。

なお、 __missing__() は __getitem__() 以外のいかなる演算に対しても呼び出され ません 。よって get() は、普通の辞書と同様に、 default_factory を使うのではなくデフォルトとして None を返します。

defaultdict オブジェクトは以下のインスタンス変数をサポートしています:

default_factory

この属性は __missing__() メソッドによって使われます。これは存在すればコンストラクタの第1引数によって初期化され、そうでなければ None になります。

バージョン 3.9 で変更: PEP 584 で規定されている合成演算子 (|) と更新演算子 (|=)が追加されました。

defaultdict の使用例

list を default_factory とすることで、キー=値ペアのシーケンスをリストの辞書へ簡単にグループ化できます。:

>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
...     d[k].append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

それぞれのキーが最初に登場したとき、マッピングにはまだ存在しません。 そのためエントリは default_factory 関数が返す空の list を使って自動的に作成されます。 list.append() 操作は新しいリストに値を追加します。 キーが再度出現した場合には、通常の参照動作が行われます(そのキーに対応するリストが返ります)。 そして list.append() 操作で別の値をリストに追加します。 このテクニックは dict.setdefault() を使った等価なものよりシンプルで速いです:

>>> d = {}
>>> for k, v in s:
...     d.setdefault(k, []).append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

default_factory を int にすると、 defaultdict を(他の言語の bag や multisetのように)要素の数え上げに便利に使うことができます:

>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
...     d[k] += 1
...
>>> sorted(d.items())
[('i', 4), ('m', 1), ('p', 2), ('s', 4)]

最初に文字が出現したときは、その文字がマッピングに存在しないので default_factory 関数が int() を呼んでデフォルトのカウント0を生成します。 インクリメント操作が各文字を数え上げます。

常に 0 を返す int() は、一定の値を返す関数の一例にすぎません。 そのような関数をより高速かつ柔軟に作るには、0 に限らず任意の定数を返せるラムダ関数を使います。

>>> def constant_factory(value):
...     return lambda: value
...
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>'

default_factory を set に設定することで、 defaultdict をセットの辞書を作るために利用することができます:

>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
>>> d = defaultdict(set)
>>> for k, v in s:
...     d[k].add(v)
...
>>> sorted(d.items())
[('blue', {2, 4}), ('red', {1, 3})]

namedtuple() 名前付きフィールドを持つタプルのファクトリ関数

名前付きタプルは、タプルの中のすべての場所に意味を割り当てて、より読みやすく自己解説的なコードを書けるようにします。通常のタプルが利用される場所ならどこでも利用でき、場所に対するインデックスの代わりに名前を使ってフィールドにアクセスできるようになります。

collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)

typename という名前の新しいタプルのサブクラスを返します。 このサブクラスでは、インデックスによるアクセスや反復に加えて、属性名でもフィールドにアクセスできるタプルに似たオブジェクトを作成できます。 インスタンスには typename と field_names を含む便利な docstring と、タプルの内容を name=value 形式で列挙する便利な __repr__() メソッドもあります。

field_names は ['x', 'y'] のような文字列のシーケンスです。 field_names には、代わりに各属性名を空白文字 (whitespace) および/またはカンマ (,) で区切った文字列を渡すこともできます。例えば、 'x y' や 'x, y' です。

アンダースコア (_) で始まる名前を除いて、 Python の正しい識別子 (identifier) ならなんでも属性名として使うことができます。正しい識別子とはアルファベット(letters), 数字(digits), アンダースコア(_) を含みますが、数字やアンダースコアで始まる名前や、 class, for, return, global, pass, raise などといった keyword は使えません。

rename が真の場合、不適切なフィールド名は自動的に位置を示す名前に置き換えられます。例えば ['abc', 'def', 'ghi', 'abc'] は、予約語の def と、重複しているフィールド名の abc が除去され、['abc', '_1', 'ghi', '_3'] に変換されます。

defaults には None あるいはデフォルト値の iterable が指定できます。 デフォルト値を持つフィールドはデフォルト値を持たないフィールドより後ろに来なければならないので、 defaults は最も右にある変数に適用されます。 例えば、 field_names が ['x', 'y', 'z'] で defaults が (1, 2) の場合、 x は必須の引数、 y は 1 がデフォルト、 z は 2 がデフォルトとなります。

もし module が指定されていれば、名前付きタプルの __module__ 属性は、指定された値に設定されます

名前付きタプルのインスタンスはインスタンスごとの辞書を持たないので、軽量で、普通のタプル以上のメモリを使用しません。

pickle 化をサポートするには、名前付きタプルのクラス定義は typename と同じ名前の変数に割り当てなければなりません。

バージョン 3.1 で変更: rename のサポートが追加されました。

バージョン 3.6 で変更: verbose と rename 引数が キーワード専用引数 になりました.

バージョン 3.6 で変更: module 引数が追加されました。

バージョン 3.7 で変更: verbose 引数と _source 属性が削除されました。

バージョン 3.7 で変更: defaults 引数と _field_defaults 属性が追加されました。

>>> # 基本的な例
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22)     # 位置引数またはキーワード引数でインスタンスを作成
>>> p[0] + p[1]             # 通常のタプル (11, 22) と同様にインデックスでアクセス可能
33
>>> x, y = p                # 通常のタプルと同様にアンパック
>>> x, y
(11, 22)
>>> p.x + p.y               # フィールドには名前でもアクセス可能
33
>>> p                       # name=value 形式の読みやすい __repr__
Point(x=11, y=22)

名前付きタプルは csv や sqlite3 モジュールが返すタプルのフィールドに名前を付けるときにとても便利です:

EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')

import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
    print(emp.name, emp.title)

import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
    print(emp.name, emp.title)

タプルから継承したメソッドに加えて、名前付きタプルは3つの追加メソッドと2つの属性をサポートしています。フィールド名との衝突を避けるために、メソッド名と属性名はアンダースコアで始まります。

classmethod somenamedtuple._make(iterable, /)

既存の sequence や Iterable から新しいインスタンスを作るクラスメソッド.

>>> t = [11, 22]
>>> Point._make(t)
Point(x=11, y=22)
somenamedtuple._asdict()

フィールド名を対応する値にマッピングする新しい dict を返します:

>>> p = Point(x=11, y=22)
>>> p._asdict()
{'x': 11, 'y': 22}

バージョン 3.1 で変更: 通常の dict の代わりに OrderedDict を返すようになりました。

バージョン 3.8 で変更: collections.OrderedDict ではなく dict を返すようになりました。Python 3.7以降は、通常の辞書で順番が保証されています。 OrderedDict 特有の機能を使いたい場合は、結果を OrderedDict(nt._asdict()) 型にキャストして使用することを推奨します。

somenamedtuple._replace(**kwargs)

指定されたフィールドを新しい値で置き換えた、新しい名前付きタプルを作って返します:

>>> p = Point(x=11, y=22)
>>> p._replace(x=33)
Point(x=33, y=22)

>>> for partnum, record in inventory.items():
...     inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())

名前付きタプルは汎用的な関数 copy.replace() にもサポートされています。

バージョン 3.13 で変更: キーワード引数が無効な場合は ValueError のかわりに TypeError が発生します。

somenamedtuple._fields

フィールド名をリストにしたタプルです。内省 (introspection) したり、既存の名前付きタプルをもとに新しい名前つきタプルを作成する時に便利です。

>>> p._fields            # フィールド名を表示
('x', 'y')

>>> Color = namedtuple('Color', 'red green blue')
>>> Pixel = namedtuple('Pixel', Point._fields + Color._fields)
>>> Pixel(11, 22, 128, 255, 0)
Pixel(x=11, y=22, red=128, green=255, blue=0)
somenamedtuple._field_defaults

フィールド名からデフォルト値への対応を持つ辞書です。

>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
>>> Account._field_defaults
{'balance': 0}
>>> Account('premium')
Account(type='premium', balance=0)

文字列に格納された名前を使って名前つきタプルから値を取得するには getattr() 関数を使います:

>>> getattr(p, 'x')
11

辞書を名前付きタプルに変換するには、 ** 演算子 (double-star-operator, 引数リストのアンパック で説明しています) を使います。:

>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)

名前付きタプルは通常の Python クラスなので、継承して機能を追加したり変更するのは容易です。次の例では計算済みフィールドと固定幅の print format を追加しています:

>>> class Point(namedtuple('Point', ['x', 'y'])):
...     __slots__ = ()
...     @property
...     def hypot(self):
...         return (self.x ** 2 + self.y ** 2) ** 0.5
...     def __str__(self):
...         return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)

>>> for p in Point(3, 4), Point(14, 5/7):
...     print(p)
Point: x= 3.000  y= 4.000  hypot= 5.000
Point: x=14.000  y= 0.714  hypot=14.018

このサブクラスは __slots__ に空のタプルをセットしています。これにより、インスタンス辞書の作成を抑制してメモリ使用量を低く保つのに役立ちます。

サブクラス化は新しいフィールドを追加するのには適していません。代わりに、新しい名前付きタプルを _fields 属性を元に作成してください:

>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))

__doc__ フィールドに直接代入することでドックストリングをカスタマイズすることが出来ます:

>>> Book = namedtuple('Book', ['id', 'title', 'authors'])
>>> Book.__doc__ += ': Hardcover book in active collection'
>>> Book.id.__doc__ = '13-digit ISBN'
>>> Book.title.__doc__ = 'Title of first printing'
>>> Book.authors.__doc__ = 'List of authors sorted by last name'

バージョン 3.5 で変更: 属性ドックストリングが書き込み可能になりました。

参考

  • 名前付きタプルに型ヒントを追加する方法については、 typing.NamedTuple を参照してください。 class キーワードを使った洗練された記法も紹介されています:

    class Component(NamedTuple):
        part_number: int
        weight: float
        description: Optional[str] = None
    
  • タプルではなく、辞書をもとにした変更可能な名前空間を作成するには types.SimpleNamespace() を参照してください。

  • dataclasses モジュールは、生成される特殊メソッドをユーザー定義クラスに自動的に追加するためのデコレータや関数を提供しています。

OrderedDict オブジェクト

順序付き辞書は普通の辞書のようですが、順序操作に関係する追加の機能があります。 組み込みの dict クラスが挿入順序を記憶しておく機能 (この新しい振る舞いは Python 3.7 で保証されるようになりました) を獲得した今となっては、順序付き辞書の重要性は薄れました。

いまだ残っている dict との差分:

  • 通常の dict は対応付けに向いているように設計されました。 挿入順序の追跡は二の次です。

  • OrderedDict は並べ替え操作に向いているように設計されました。 空間効率、反復処理の速度、更新操作のパフォーマンスは二の次です。

  • OrderedDict のアルゴリズムは、頻繁な並べ替え処理を dict よりもうまく扱うことができます。後述のレシピに示されている通り、この性質はさまざまな種類の LRU キャッシュの実装に適しています。

  • OrderedDict に対する等価演算は突き合わせ順序もチェックします。

    組み込みの dict では、順序を考慮した等価演算は p == q and all(k1 == k2 for k1, k2 in zip(p, q)) で実現することができます。

  • OrderedDict の popitem() メソッドはシグネチャが異なります。 どの要素を取り出すかを指定するオプション引数を受け付けます。

    組み込みの dict の場合、 OrderedDict の od.popitem(last=True) と同じ機能は、最も右側の (最後の) 要素を取り出すことが保証されている d.popitem() が果たします。

    組み込みの dict の場合、 OrderedDict の od.popitem(last=False) は (k := next(iter(d)), d.pop(k)) で実現できます。これにより、該当する要素のうちで最も左側の (先頭の) ものを辞書から削除して返すことができます。

  • OrderedDict には、要素を先頭または末尾に効率よく移動する move_to_end() メソッドがあります。

    組み込みの dict の場合、キーと値のペアを最も右側 (末尾) に移動する OrderedDict の od.move_to_end(k, last=True) は d[k] = d.pop(k) で実現できます。

    組み込みの dict では、キーと値のペアを最も左側 (先頭) に移動する OrderedDict の od.move_to_end(k, last=False) を実現する効率の良い方法はありません。

  • Python 3.8 より前の dict には __reversed__() メソッドがありませんでした。

class collections.OrderedDict(**kwargs)
class collections.OrderedDict(mapping, /, **kwargs)
class collections.OrderedDict(iterable, /, **kwargs)

辞書の順序を並べ直すためのメソッドを持つ dict のサブクラスのインスタンスを返します。

Added in version 3.1.

popitem(last=True)

順序付き辞書の popitem() メソッドは、(key, value) 対を返して消去します。この対は last が真なら LIFO で、偽なら FIFO で返されます。

move_to_end(key, last=True)

存在する key を順序付き辞書の先頭または末尾に移動します。要素は last が真 (デフォルト) の場合に最も右側すなわち末尾に移動します。また last が偽の場合には先頭に移動します。指定した key が存在しない場合は KeyError を送出します。

>>> d = OrderedDict.fromkeys('abcde')
>>> d.move_to_end('b')
>>> ''.join(d)
'acdeb'
>>> d.move_to_end('b', last=False)
>>> ''.join(d)
'bacde'

Added in version 3.2.

通常のマッピングのメソッドに加え、順序付き辞書は reversed() による逆順の反復もサポートしています。

OrderedDict オブジェクト同士の等価性の比較は順序を考慮し、ほぼ list(od1.items())==list(od2.items()) と等価です。

OrderedDict オブジェクトと他の Mapping オブジェクトの等価性の比較では、通常の辞書と同様に順序は考慮されません。 このため、通常の辞書を使う場所ならどこでも OrderedDict オブジェクトで置き換えられます。

バージョン 3.5 で変更: OrderedDict の項目、キー、値の ビュー が reversed() による逆順の反復をサポートするようになりました。

バージョン 3.6 で変更: PEP 468 の受理によって、OrderedDict のコンストラクタと、update() メソッドに渡したキーワード引数の順序は保持されます。

バージョン 3.9 で変更: PEP 584 で規定されている合成演算子 (|) と更新演算子 (|=)が追加されました。

OrderedDict の例とレシピ

キーが 最後に 追加されたときの順序を記憶する、順序付き辞書の変種を作るのは簡単です。 新しい値が既存の値を上書きする場合、元々の挿入位置が最後尾へ変更されます:

class LastUpdatedOrderedDict(OrderedDict):
    'キーが最後に更新された順に要素を保存する'

    def __setitem__(self, key, value):
        super().__setitem__(key, value)
        self.move_to_end(key)

OrderedDict は、@functools.lru_cache の変種を実装する際にも役立ちます:

from collections import OrderedDict
from time import monotonic

class TimeBoundedLRU:
    "古いエントリーを無効化して更新する LRU キャッシュ"

    def __init__(self, func, maxsize=128, maxage=30):
        self.cache = OrderedDict()      # { args : (timestamp, result)}
        self.func = func
        self.maxsize = maxsize
        self.maxage = maxage

    def __call__(self, *args):
        if args in self.cache:
            self.cache.move_to_end(args)
            timestamp, result = self.cache[args]
            if monotonic() - timestamp <= self.maxage:
                return result
        result = self.func(*args)
        self.cache[args] = monotonic(), result
        if len(self.cache) > self.maxsize:
            self.cache.popitem(last=False)
        return result
class MultiHitLRUCache:
    """ 結果が複数回要求されるまで
        キャッシュへの保存を遅らせる LRU キャッシュ。


        一度しか要求されない結果で LRU キャッシュが置き換わるのを防ぐため、
        同じ要求が複数回行われるまでキャッシュに保存しない。


    """

    def __init__(self, func, maxsize=128, maxrequests=4096, cache_after=1):
        self.requests = OrderedDict()   # { uncached_key : request_count }
        self.cache = OrderedDict()      # { cached_key : function_result }
        self.func = func
        self.maxrequests = maxrequests  # キャッシュにない要求の最大数
        self.maxsize = maxsize          # 保存する戻り値の最大数
        self.cache_after = cache_after

    def __call__(self, *args):
        if args in self.cache:
            self.cache.move_to_end(args)
            return self.cache[args]
        result = self.func(*args)
        self.requests[args] = self.requests.get(args, 0) + 1
        if self.requests[args] <= self.cache_after:
            self.requests.move_to_end(args)
            if len(self.requests) > self.maxrequests:
                self.requests.popitem(last=False)
        else:
            self.requests.pop(args, None)
            self.cache[args] = result
            if len(self.cache) > self.maxsize:
                self.cache.popitem(last=False)
        return result

UserDict オブジェクト

クラス UserDict は、辞書オブジェクトのラッパとしてはたらきます。このクラスの必要性は、 dict から直接的にサブクラス化できる能力に部分的に取って代わられました; しかし、根底の辞書に属性としてアクセスできるので、このクラスを使った方が簡単になることもあります。

class collections.UserDict(**kwargs)
class collections.UserDict(mapping, /, **kwargs)
class collections.UserDict(iterable, /, **kwargs)

辞書をシミュレートするクラスです。 インスタンスの内容は通常の辞書に保存され、UserDict インスタンスの data 属性を通してアクセスできます。 引数が指定された場合は、通常の辞書と同様に data の初期化に使われます。

マッピングのメソッドと演算をサポートするのに加え、UserDict インスタンスは次の属性を提供します:

data

UserDict クラスの内容を保存するために使われる実際の辞書です。

UserDict インスタンスは、次のメソッドもオーバーライドします:

popitem()

ラップしている辞書から (key, value) のペアを削除して返します。 ペアは data.popitem() と同じ順序で返されます (デフォルトの dict.popitem() の場合、この順序は LIFO です)。 辞書が空の場合は KeyError を送出します。

UserList オブジェクト

このクラスはリストオブジェクトのラッパとしてはたらきます。これは独自のリスト風クラスの基底クラスとして便利で、既存のメソッドをオーバーライドしたり新しいメソッドを加えたりできます。こうして、リストに新しい振る舞いを加えられます。

このクラスの必要性は、 list から直接的にサブクラス化できる能力に部分的に取って代わられました; しかし、根底のリストに属性としてアクセスできるので、このクラスを使った方が簡単になることもあります。

class collections.UserList([list])

リストをシミュレートするクラスです。インスタンスの内容は通常のリストに保存され、 UserList インスタンスの data 属性を通してアクセスできます。インスタンスの内容は最初に list のコピーに設定されますが、デフォルトでは空リスト [] です。 list は何らかのイテラブル、例えば通常の Python リストや UserList オブジェクト、です。

ミュータブルシーケンスのメソッドと演算をサポートするのに加え、 UserList インスタンスは以下の属性を提供します:

data

UserList クラスの内容を保存するために使われる実際の list オブジェクトです。

サブクラス化の要件: UserList のサブクラスは引数なしか、あるいは一つの引数のどちらかとともに呼び出せるコンストラクタを提供することが期待されています。新しいシーケンスを返すリスト演算は現在の実装クラスのインスタンスを作成しようとします。そのために、データ元として使われるシーケンスオブジェクトである一つのパラメータとともにコンストラクタを呼び出せると想定しています。

派生クラスがこの要求に従いたくないならば、このクラスがサポートしているすべての特殊メソッドはオーバーライドされる必要があります。その場合に提供される必要のあるメソッドについての情報は、ソースを参考にしてください。

UserString オブジェクト

クラス UserString は、文字列オブジェクトのラッパとしてはたらきます。このクラスの必要性は、 str から直接的にサブクラス化できる能力に部分的に取って代わられました; しかし、根底の文字列に属性としてアクセスできるので、このクラスを使った方が簡単になることもあります。

class collections.UserString(seq)

文字列オブジェクトをシミュレートするクラスです。 インスタンスの内容は通常の文字列に保存され、 UserString インスタンスの data 属性を通してアクセスできます。 インスタンスの内容には最初に seq のコピーが設定されます。 seq 引数は、組み込みの str() 関数で文字列に変換できる任意のオブジェクトです。

文字列のメソッドと演算をサポートするのに加え、 UserString インスタンスは次の属性を提供します:

data

UserString クラスの内容を保存するために使われる実際の str オブジェクトです。

バージョン 3.5 で変更: 新たなメソッド __getnewargs__, __rmod__, casefold, format_map, isprintable, maketrans。