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'