8.3. "collections" --- 高性能なコンテナ・データ型
*************************************************

バージョン 2.4 で追加.

**Source code:** Lib/collections.py and Lib/_abcoll.py

======================================================================

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

+-----------------------+----------------------------------------------------------------------+-----------------------------+
| "namedtuple()"        | 名前付きフィールドを持つタプルのサブクラスを作成するファクトリ関数   | バージョン 2.6 で追加.      |
+-----------------------+----------------------------------------------------------------------+-----------------------------+
| "deque"               | 両端における append や pop を高速に行えるリスト風のコンテナ          | バージョン 2.4 で追加.      |
+-----------------------+----------------------------------------------------------------------+-----------------------------+
| "Counter"             | ハッシュ可能なオブジェクトを数え上げる辞書のサブクラス               | バージョン 2.7 で追加.      |
+-----------------------+----------------------------------------------------------------------+-----------------------------+
| "OrderedDict"         | 項目が追加された順序を記憶する辞書のサブクラス                       | バージョン 2.7 で追加.      |
+-----------------------+----------------------------------------------------------------------+-----------------------------+
| "defaultdict"         | ファクトリ関数を呼び出して存在しない値を供給する辞書のサブクラス     | バージョン 2.5 で追加.      |
+-----------------------+----------------------------------------------------------------------+-----------------------------+

コンテナ型の作成に加えて、 collections モジュールは幾つかの ABC
(abstract base classes = 抽象基底クラス) を提供しています。 ABC はクラ
スが特定のインタフェース持っているかどうか、たとえばハッシュ可能である
かやマッピングであるかを判定するのに利用します。


8.3.1. "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

   バージョン 2.7 で追加.

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

   elements()

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

      >>> c = Counter(a=4, b=2, c=0, d=-2)
      >>> list(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})

   普通の辞書のメソッドは、以下の 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 += Counter()                  # 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})

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

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

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

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

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

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

参考:

  * Python 2.5 向けの Counter class と、それより前の Python 2.4 向け
    の Bag recipe 。

  * 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.2. "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)" のコストを必要とします。

   バージョン 2.4 で追加.

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

   バージョン 2.6 で変更: *maxlen* パラメータを追加しました。

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

   append(x)

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

   appendleft(x)

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

   clear()

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

   count(x)

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

      バージョン 2.7 で追加.

   extend(iterable)

      イテレータ化可能な引数 iterable から得られる要素を deque の右側
      に追加し拡張します。

   extendleft(iterable)

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

   pop()

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

   popleft()

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

   remove(value)

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

      バージョン 2.5 で追加.

   reverse()

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

      バージョン 2.7 で追加.

   rotate(n=1)

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

      When the deque is not empty, rotating one step to the right is
      equivalent to "d.appendleft(d.pop())", and rotating one step to
      the left is equivalent to "d.append(d.popleft())".

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

   maxlen

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

      バージョン 2.7 で追加.

上記の操作のほかにも、deque は次のような操作をサポートしています: イテ
レータ化、pickle、 "len(d)", "reversed(d)", "copy.copy(d)",
"copy.deepcopy(d)", "in" 演算子による包含検査、そして "d[-1]" などの添
え字による参照。両端についてインデックスアクセスは O(1) ですが、中央部
分については O(n) の遅さです。高速なランダムアクセスが必要ならリストを
使ってください。

例:

   >>> 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.2.1. "deque" のレシピ
-------------------------

この節では deque をつかったさまざまなアプローチを紹介します。

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

   def tail(filename, n=10):
       'Return the last n lines of a file'
       return deque(open(filename), n)

別のアプローチとして deque を右に append して左に pop して使うことで追
加した要素を維持するのに使えます:

   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 / float(n)

"rotate()" メソッドのおかげで、 "deque" の一部を切り出したり削除したり
できることになります。たとえば "del d[n]" の純粋な Python 実装では pop
したい要素まで "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.3. "defaultdict" オブジェクト
=================================

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

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

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

   バージョン 2.5 で追加.

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

   __missing__(key)

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

      もし "default_factory" 属性が "None" でなければ、このメソッドは
      "default_factory" を引数なしで呼び出し、あたえられた *key* に対
      応するデフォルト値を作ります。そしてこの値を *key* に対応する値
      を辞書に登録して返ります。

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

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

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

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

   default_factory

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


8.3.3.1. "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)
...
>>> 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)
...
>>> 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
...
>>> d.items()
[('i', 4), ('p', 2), ('s', 4), ('m', 1)]

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

常に0を返す "int()" は特殊な関数でした。定数を生成するより速くて柔軟な
方法は、 0に限らず何でも定数を生成する "itertools.repeat()" を使うこと
です。

>>> def constant_factory(value):
...     return itertools.repeat(value).next
>>> 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)
...
>>> d.items()
[('blue', set([2, 4])), ('red', set([1, 3]))]


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

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

collections.namedtuple(typename, field_names[, verbose=False][, rename=False])

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

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

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

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

   *verbose* が真なら、クラスを作る直前にクラス定義が表示されます。

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

   バージョン 2.6 で追加.

   バージョン 2.7 で変更: *rename* のサポートを追加しました。

例:

   >>> Point = namedtuple('Point', ['x', 'y'], verbose=True)
   class Point(tuple):
       'Point(x, y)'

       __slots__ = ()

       _fields = ('x', 'y')

       def __new__(_cls, x, y):
           'Create new instance of Point(x, y)'
           return _tuple.__new__(_cls, (x, y))

       @classmethod
       def _make(cls, iterable, new=tuple.__new__, len=len):
           'Make a new Point object from a sequence or iterable'
           result = new(cls, iterable)
           if len(result) != 2:
               raise TypeError('Expected 2 arguments, got %d' % len(result))
           return result

       def __repr__(self):
           'Return a nicely formatted representation string'
           return 'Point(x=%r, y=%r)' % self

       def _asdict(self):
           'Return a new OrderedDict which maps field names to their values'
           return OrderedDict(zip(self._fields, self))

       def _replace(_self, **kwds):
           'Return a new Point object replacing specified fields with new values'
           result = _self._make(map(kwds.pop, ('x', 'y'), _self))
           if kwds:
               raise ValueError('Got unexpected field names: %r' % kwds.keys())
           return result

       def __getnewargs__(self):
           'Return self as a plain tuple.  Used by copy and pickle.'
           return tuple(self)

       __dict__ = _property(_asdict)

       def __getstate__(self):
           'Exclude the OrderedDict from pickling'
           pass

       x = _property(_itemgetter(0), doc='Alias for field number 0')

       y = _property(_itemgetter(1), doc='Alias for field number 1')



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

名前付きタプルは "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つの追加メソッド
と一つの属性をサポートしています。フィールド名との衝突を避けるためにメ
ソッド名と属性名はアンダースコアで始まります。

classmethod somenamedtuple._make(iterable)

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

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

somenamedtuple._asdict()

   フィールド名を対応する値にマッピングする新しい順序付き辞書
   ("OrderedDict") を返します:

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

   バージョン 2.7 で変更: 通常の "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._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',))

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

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

列挙型定数は名前付きタプルでも実装できますが、クラス定義を利用した方が
シンプルで効率的です:

>>> Status = namedtuple('Status', 'open pending closed')._make(range(3))
>>> Status.open, Status.pending, Status.closed
(0, 1, 2)
>>> class Status:
...     open, pending, closed = range(3)

参考: Python 2.4 向けの Named tuple recipe 。


8.3.5. "OrderedDict" オブジェクト
=================================

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

class collections.OrderedDict([items])

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

   バージョン 2.7 で追加.

OrderedDict.popitem(last=True)

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

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

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

"OrderedDict" コンストラクタと "update()" メソッドは、どちらもキーワー
ド引数を受け付けますが、その順序は失われます。これは、Python の関数呼
び出しの意味づけにおいて、キーワード引数は順序付けされていない辞書を用
いて渡されるからです。

参考: Python 2.4 以降で動作する、 Equivalent OrderedDict recipe 。


8.3.5.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.6. コレクション抽象基底クラス
=================================

collections モジュールは以下の *ABC (抽象基底クラス)* を提供します:

+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| ABC                       | 継承しているクラス    | 抽象メソッド           | mixin メソッド                                       |
+===========================+=======================+========================+======================================================+
| "Container"               |                       | "__contains__"         |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Hashable"                |                       | "__hash__"             |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Iterable"                |                       | "__iter__"             |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Iterator"                | "Iterable"            | "next"                 | "__iter__"                                           |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Sized"                   |                       | "__len__"              |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Callable"                |                       | "__call__"             |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Sequence"                | "Sized", "Iterable",  | "__getitem__",         | "__contains__", "__iter__", "__reversed__", "index", |
|                           | "Container"           | "__len__"              | "count"                                              |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "MutableSequence"         | "Sequence"            | "__getitem__",         | "Sequence" から継承したメソッドと、 "append",        |
|                           |                       | "__setitem__",         | "reverse", "extend", "pop", "remove", "__iadd__"     |
|                           |                       | "__delitem__",         |                                                      |
|                           |                       | "__len__", "insert"    |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Set"                     | "Sized", "Iterable",  | "__contains__",        | "__le__", "__lt__", "__eq__", "__ne__", "__gt__",    |
|                           | "Container"           | "__iter__", "__len__"  | "__ge__", "__and__", "__or__", "__sub__", "__xor__", |
|                           |                       |                        | "isdisjoint"                                         |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "MutableSet"              | "Set"                 | "__contains__",        | "Set" から継承したメソッドと、 "clear", "pop",       |
|                           |                       | "__iter__", "__len__", | "remove", "__ior__", "__iand__", "__ixor__",         |
|                           |                       | "add", "discard"       | "__isub__"                                           |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "Mapping"                 | "Sized", "Iterable",  | "__getitem__",         | "__contains__", "keys", "items", "values", "get",    |
|                           | "Container"           | "__iter__", "__len__"  | "__eq__", "__ne__"                                   |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "MutableMapping"          | "Mapping"             | "__getitem__",         | "Mapping" から継承したメソッドと、 "pop", "popitem", |
|                           |                       | "__setitem__",         | "clear", "update", "setdefault"                      |
|                           |                       | "__delitem__",         |                                                      |
|                           |                       | "__iter__", "__len__"  |                                                      |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "MappingView"             | "Sized"               |                        | "__len__"                                            |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "ItemsView"               | "MappingView", "Set"  |                        | "__contains__", "__iter__"                           |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "KeysView"                | "MappingView", "Set"  |                        | "__contains__", "__iter__"                           |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+
| "ValuesView"              | "MappingView"         |                        | "__contains__", "__iter__"                           |
+---------------------------+-----------------------+------------------------+------------------------------------------------------+

class collections.Container
class collections.Hashable
class collections.Sized
class collections.Callable

   それぞれメソッド "__contains__()", "__hash__()", "__len__()",
   "__call__()" を提供するクラスの ABC です。

class collections.Iterable

   "__iter__()" メソッドを提供するクラスの ABC です。 *iterable* の定
   義も参照してください。

class collections.Iterator

   "__iter__()" メソッドと "next()" メソッドを提供するクラスの ABC で
   す。 *iterator* の定義も参照してください。

class collections.Sequence
class collections.MutableSequence

   読み出し専用でミュータブルな *シーケンス* の ABC です。

class collections.Set
class collections.MutableSet

   読み出し専用でミュータブルな集合の ABC です。

class collections.Mapping
class collections.MutableMapping

   読み出し専用でミュータブルな *マッピング* の ABC です。

class collections.MappingView
class collections.ItemsView
class collections.KeysView
class collections.ValuesView

   マッピング、要素、キー、値の *ビュー* の ABC です。

これらの ABC はクラスやインスタンスが特定の機能を提供しているかどうか
を調べるのに使えます。例えば:

   size = None
   if isinstance(myvar, collections.Sized):
       size = len(myvar)

幾つかの ABC はコンテナ型 API を提供するクラスを開発するのを助ける
mixin 型としても使えます。例えば、 "Set" API を提供するクラスを作る場
合、3つの基本になる抽象メソッド "__contains__()", "__iter__()",
"__len__()" だけが必要です。 ABC が残りの "__and__()" や
"isdisjoint()" といったメソッドを提供します:

   class ListBasedSet(collections.Set):
        ''' Alternate set implementation favoring space over speed
            and not requiring the set elements to be hashable. '''
        def __init__(self, iterable):
            self.elements = lst = []
            for value in iterable:
                if value not in lst:
                    lst.append(value)

        def __iter__(self):
            return iter(self.elements)

        def __contains__(self, value):
            return value in self.elements

        def __len__(self):
            return len(self.elements)

   s1 = ListBasedSet('abcdef')
   s2 = ListBasedSet('defghi')
   overlap = s1 & s2            # The __and__() method is supported automatically

"Set" と "MutableSet" を mixin 型として利用するときの注意点:

1. 幾つかの set の操作は新しい set を作るので、デフォルトの mixin
   メソ ッドは iterable から新しいインスタンスを作成する方法を必要とし
   ます 。クラスのコンストラクタは "ClassName(iterable)" の形のシグネ
   チャを 持つと仮定されます。内部の "_from_iterable()" というクラスメ
   ソッド が "cls(iterable)" を呼び出して新しい set を作る部分でこの仮
   定が使 われています。コンストラクタのシグネチャが異なるクラスで
   "Set" を使 う場合は、 iterable 引数から新しいインスタンスを生成する
   ように "_from_iterable()" をオーバーライドする必要があります。

2. (たぶん意味はそのままに速度を向上する目的で)比較をオーバーライド
   す る場合、 "__le__()" と "__ge__()" だけを再定義すれば、その他の演
   算 は自動的に追随します。

3. "Set" mixin型は set のハッシュ値を計算する "_hash()" メソッドを
   提供 しますが、すべての set が hashable や immutable とは限らないの
   で、 "__hash__()" は提供しません。 mixin を使ってハッシュ可能な set
   を作 る場合は、 "Set" と "Hashable" の両方を継承して、 "__hash__ =
   Set._hash" と定義してください。

参考:

  * "MutableSet" を使った例として OrderedSet recipe。

  * ABCs についての詳細は、 "abc" モジュールと **PEP 3119** を参照し
    て ください。
