8.3. collections — コンテナデータ型

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


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

namedtuple() 名前付きフィールドを持つタプルのサブクラスを作成するファクトリ関数
deque 両端における append や pop を高速に行えるリスト風のコンテナ
ChainMap 複数のマッピングの一つのビューを作成する辞書風のクラス
Counter ハッシュ可能なオブジェクトを数え上げる辞書のサブクラス
OrderedDict 項目が追加された順序を記憶する辞書のサブクラス
defaultdict ファクトリ関数を呼び出して存在しない値を供給する辞書のサブクラス
UserDict 辞書のサブクラス化を簡単にする辞書オブジェクトのラッパ
UserList リストのサブクラス化を簡単にするリストオブジェクトのラッパ
UserString 文字列のサブクラス化を簡単にする文字列オブジェクトのラッパ

バージョン 3.3 で変更: コレクション抽象基底クラスcollections.abc モジュールに移動されました。後方互換性のため、それらは引き続きこのモジュールでも利用できます。

8.3.1. ChainMap オブジェクト

バージョン 3.3 で追加.

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

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

class collections.ChainMap(*maps)

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

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

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

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

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

maps

マッピングのユーザがアップデートできるリストです。このリストは最初に探されるものから最後に探されるものの順に並んでいます。これが唯一のソートされた状態であり、変更してマッピングが探される順番を変更できます。このリストは常に一つ以上のマッピングを含んでいなければなりません。

new_child(m=None)

新しい辞書の後ろに現在のインスタンスにある全ての辞書が続いたものを持つ、新しい ChainMap を返します。 m が指定された場合、それがマッピングのリストの先頭の新しい辞書になります; 指定されていない場合、 d.new_child()ChainMap({}, *d.maps) と同等となるように空の辞書が使われます。このメソッドは、親マッピングを変更することなく値を更新できるサブコンテキストを作成するのに使われます。

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

parents

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

参考

8.3.1.1. 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}

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']                # Get first key in the chain of contexts
d['x'] = 1            # Set value in current context
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):
    'Variant of ChainMap that allows direct updates to inner scopes'

    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'         # update an existing key two levels down
>>> d['snake'] = 'red'           # new keys get added to the topmost dict
>>> del d['elephant']            # remove an existing key one level down
DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})

8.3.2. Counter オブジェクト

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

>>> # Tally occurrences of words in a list
>>> cnt = Counter()
>>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
...     cnt[word] += 1
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})

>>> # Find the ten most common words in Hamlet
>>> 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([iterable-or-mapping])

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

バージョン 3.1 で追加.

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

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])

最も多い n 要素を、カウントが多いものから少ないものまで順に並べたリストを返します。 n が省略されるか None であれば、 most_common() はカウンタの すべての 要素を返します。等しいカウントの要素は任意に並べられます:

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

要素から 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})

バージョン 3.2 で追加.

普通の辞書のメソッドは、以下の 2 つのメソッドがカウンタに対して異なる振る舞いをするのを除き、 Counter オブジェクトにも利用できます。

fromkeys(iterable)

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

update([iterable-or-mapping])

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

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

sum(c.values())                 # total of all counts
c.clear()                       # reset all counts
list(c)                         # list unique elements
set(c)                          # convert to a set
dict(c)                         # convert to a regular dictionary
c.items()                       # convert to a list of (elem, cnt) pairs
Counter(dict(list_of_pairs))    # convert from a list of (elem, cnt) pairs
c.most_common()[:-n-1:-1]       # n least common elements
+c                              # remove zero and negative counts

Counter オブジェクトを組み合わせて多重集合 (1 以上のカウントをもつカウンタ) を作るために、いくつかの数学演算が提供されています。足し算と引き算は、対応する要素を足したり引いたりすることによってカウンタを組み合わせます。積集合と和集合は、対応するカウントの最大値と最小値を返します。それぞれの演算はカウントに符号がついた入力を受け付けますが、カウントが 0 以下である結果は出力から除かれます。

>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d                       # add two counters together:  c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d                       # subtract (keeping only positive counts)
Counter({'a': 2})
>>> c & d                       # intersection:  min(c[x], d[x]) 
Counter({'a': 1, 'b': 1})
>>> c | d                       # union:  max(c[x], d[x])
Counter({'a': 3, 'b': 2})

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

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

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

注釈

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

  • 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

8.3.3. 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 オブジェクトは以下のようなメソッドをサポートしています:

append(x)

x を deque の右側につけ加えます。

appendleft(x)

x を deque の左側につけ加えます。

clear()

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

copy()

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

バージョン 3.5 で追加.

count(x)

deque の x に等しい要素を数え上げます。

バージョン 3.2 で追加.

extend(iterable)

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

extendleft(iterable)

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

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

deque 内の x の位置を返します (インデックス start からインデックス stop の両端を含む範囲で)。最初のマッチを返すか、見つからない場合には ValueError を発生させます。

バージョン 3.5 で追加.

insert(i, x)

x を deque の位置 i に挿入します。

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

バージョン 3.5 で追加.

pop()

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

popleft()

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

remove(value)

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

reverse()

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

バージョン 3.2 で追加.

rotate(n)

deque の要素を全体で n 単位だけ右に循環させます。n が負の値の場合は左に循環させます。一単位右に循環させることは d.appendleft(d.pop()) と等価です。

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

maxlen

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

バージョン 3.1 で追加.

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

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

例:

>>> from collections import deque
>>> d = deque('ghi')                 # make a new deque with three items
>>> for elem in d:                   # iterate over the deque's elements
...     print(elem.upper())
G
H
I

>>> d.append('j')                    # add a new entry to the right side
>>> d.appendleft('f')                # add a new entry to the left side
>>> d                                # show the representation of the deque
deque(['f', 'g', 'h', 'i', 'j'])

>>> d.pop()                          # return and remove the rightmost item
'j'
>>> d.popleft()                      # return and remove the leftmost item
'f'
>>> list(d)                          # list the contents of the deque
['g', 'h', 'i']
>>> d[0]                             # peek at leftmost item
'g'
>>> d[-1]                            # peek at rightmost item
'i'

>>> list(reversed(d))                # list the contents of a deque in reverse
['i', 'h', 'g']
>>> 'h' in d                         # search the deque
True
>>> d.extend('jkl')                  # add multiple elements at once
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1)                      # right rotation
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1)                     # left rotation
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])

>>> deque(reversed(d))               # make a new deque in reverse order
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear()                        # empty the deque
>>> d.pop()                          # cannot pop from an empty 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() reverses the input order
>>> d
deque(['c', 'b', 'a'])

8.3.3.1. deque のレシピ

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

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

def tail(filename, n=10):
    'Return the last n lines of a file'
    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
    # http://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

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 を実装するのも簡単です。

8.3.4. defaultdict オブジェクト

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

新しいディクショナリ様のオブジェクトを返します。 defaultdict は組み込みの dict のサブクラスです。メソッドをオーバーライドし、書き込み可能なインスタンス変数を1つ追加している以外は dict クラスと同じです。同じ部分については以下では省略されています。

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

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 になります。

8.3.4.1. defaultdict の使用例

listdefault_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_factoryint にすると、 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_factoryset に設定することで、 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})]

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

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

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

typename という名前の tuple の新しいサブクラスを返します。新しいサブクラスは、 tuple に似ているけれどもインデックスやイテレータだけでなく属性名によるアクセスもできるオブジェクトを作るのに使います。このサブクラスのインスタンスは、わかりやすい docstring (型名と属性名が入っています) や、 tuple の内容を name=value という形のリストで返す使いやすい __repr__() も持っています。

The field_names are a sequence of strings such as ['x', 'y']. Alternatively, field_names can be a single string with each fieldname separated by whitespace and/or commas, for example 'x y' or 'x, y'.

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

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

verbose が真なら、クラス定義が構築された後に表示されます。このオプションは時代遅れです。代わりに、 _source 属性を表示するのが簡潔です。

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

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

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

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

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

>>> # Basic example
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22)     # instantiate with positional or keyword arguments
>>> p[0] + p[1]             # indexable like the plain tuple (11, 22)
33
>>> x, y = p                # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y               # fields also accessible by name
33
>>> p                       # readable __repr__ with a name=value style
Point(x=11, y=22)

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

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()

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

>>> p = Point(x=11, y=22)
>>> p._asdict()
OrderedDict([('x', 11), ('y', 22)])

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

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())
somenamedtuple._source

名前付きタプルクラスを作成するのに使われる pure Python ソースコードの文字列です。このソースは名前付きタプルを自己文書化します。これは表示したり、 exec() を使って実行したり、ファイルに保存してインポートしたりできます。

バージョン 3.3 で追加.

somenamedtuple._fields

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

>>> p._fields            # view the field names
('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)

文字列に格納された名前を使って名前つきタプルから値を取得するには 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 で変更: 属性ドックストリングが書き込み可能になりました。

_replace() でプロトタイプのインスタンスをカスタマイズする方法で、デフォルト値を実装できます:

>>> Account = namedtuple('Account', 'owner balance transaction_count')
>>> default_account = Account('<owner name>', 0.0, 0)
>>> johns_account = default_account._replace(owner='John')
>>> janes_account = default_account._replace(owner='Jane')

参考

8.3.6. OrderedDict オブジェクト

順序付き辞書 (ordered dictionary) は、ちょうど普通の辞書と同じようなものですが、項目が挿入された順序を記憶します。順序付き辞書に渡ってイテレートするとき、項目はそのキーが最初に追加された順序で返されます。

class collections.OrderedDict([items])

通常の dict メソッドをサポートする、辞書のサブクラスのインスタンスを返します。 OrderedDict は、キーが最初に追加された順序を記憶します。新しい項目が既存の項目を上書きしても、元の挿入位置は変わらないままです。項目を削除して再挿入するとそれが最後に移動します。

バージョン 3.1 で追加.

popitem(last=True)

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

move_to_end(key, last=True)

既存の key を順序付き辞書の両端に移動します。項目は、 last が真 (デフォルト) なら右端に、 last が偽なら最初に移動されます。 key が存在しなければ KeyError を送出します:

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

バージョン 3.2 で追加.

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

OrderedDict 間の等価判定は順序が影響し、 list(od1.items())==list(od2.items()) のように実装されます。 OrderedDict オブジェクトと他のマッピング (Mapping) オブジェクトの等価判定は、順序に影響されず、通常の辞書と同様です。これによって、 OrderedDict オブジェクトは通常の辞書が使われるところならどこでも使用できます。

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

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

8.3.6.1. OrderedDict の例とレシピ

順序付き辞書は挿入順序を記憶するので、ソートと組み合わせて使うことで、ソートされた辞書を作れます:

>>> # regular unsorted dictionary
>>> d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}

>>> # dictionary sorted by key
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

>>> # dictionary sorted by value
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

>>> # dictionary sorted by length of the key string
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])

この新しい順序付き辞書は、項目が削除されてもソートされた順序を保持します。しかし、キーが追加されるとき、そのキーは最後に追加され、ソートは保持されません。

キーが 最後に 挿入された順序を記憶するような、順序付き辞書の変種を作るのも簡単です。新しい項目が既存の項目を上書きしたら、元の挿入位置は最後に移動します:

class LastUpdatedOrderedDict(OrderedDict):
    'Store items in the order the keys were last added'

    def __setitem__(self, key, value):
        if key in self:
            del self[key]
        OrderedDict.__setitem__(self, key, value)

順序付き辞書と Counter クラスを組み合わせると、要素が最初に現れた順を記憶するカウンタができます:

class OrderedCounter(Counter, OrderedDict):
    'Counter that remembers the order elements are first encountered'

    def __repr__(self):
        return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

    def __reduce__(self):
        return self.__class__, (OrderedDict(self),)

8.3.7. UserDict オブジェクト

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

class collections.UserDict([initialdata])

辞書をシミュレートするクラスです。インスタンスの内容は通常の辞書に保存され、 UserDict インスタンスの data 属性を通してアクセスできます。 initialdata が与えられれば、 data はその内容で初期化されます。他の目的のために使えるように、 initialdata への参照が保存されないことがあるということに注意してください。

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

data

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

8.3.8. UserList オブジェクト

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

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

class collections.UserList([list])

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

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

data

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

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

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

8.3.9. UserString オブジェクト

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

class collections.UserString([sequence])

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

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