LoginSignup
7
6

More than 5 years have passed since last update.

ChainMapの主な特徴

Posted at

Python 3.3よりcollections標準ライブラリのChainMapというクラスが利用できますが、主な特徴について備忘録として書き留めておきます。

ChainMapは、複数の辞書を集めて一つの辞書を作るのに使用します。

同じことをdictで行うには、この記事で説明されているように、複数の辞書をマージして元々の辞書の要素を含んだ新しい辞書を作成するかと思います。

これに対し、ChainMapは、新しいオブジェクトに要素をコピーするわけではなく、元々の辞書を参照として保持するため、元の辞書が変更されても、ChainMapオブジェクトを更新する必要がありません。

例えば、次のようなサンプルを考えます。

from collections import ChainMap

d1 = {'A': 1, 'B':2}
d2 = {'C': 3, 'D':4}

cm = ChainMap(d1, d2)

ここで、d1に要素を追加すると、cmでもその要素が取得できることが分かります。

>>> d1['E'] = 5
>>> cm['E']
5

mapsプロパティで、元となる辞書を取得できます。

>>> cm.maps
[{'E': 5, 'B': 2, 'A': 1}, {'D': 4, 'C': 3}]

元の辞書間で重複するキーがある場合、手前の辞書にある要素が優先されます。

>>> d1['D'] = 6
>>> cm.maps
[{'E': 5, 'B': 2, 'A': 1, 'D': 6}, {'D': 4, 'C': 3}]
>>> cm['D']
6

また、元となる辞書はビルトインのdictオブジェクトに限らず、Mappingオブジェクトを指定することができます。次の例は、同じ標準ライブラリにあるUserDictをソースの辞書に使用した例です。

from collections import UserDict

class MyDict(UserDict):

    def __getitem__(self, key):
        if key not in self.data:
            return 'Not found'
        else:
            return self.data[key]

md1 = MyDict(d1)
md2 = MyDict(d2)

cm2 = ChainMap(md1, md2)

この例では、md2にキーCがあっても、md1__getitem__が先に呼ばれてしまうため、"Not found"が返されます。

>>> cm2['C']
'Not found'
7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6