Python 3.3 a ChainMap
クラスが collections
モジュールに追加されました:
ChainMapクラスは、多数のマッピングを迅速にリンクして、単一のユニットとして扱うことができるように提供されています。多くの場合、新しい辞書を作成して複数のupdate()呼び出しを実行するよりもはるかに高速です。
例:
_>>> from collections import ChainMap
>>> x = {'a': 1, 'b': 2}
>>> y = {'b': 10, 'c': 11}
>>> z = ChainMap(y, x)
>>> for k, v in z.items():
print(k, v)
a 1
c 11
b 10
_
この問題 によって動機付けられ、 this one によって公開されました(PEP
は作成されませんでした)。
私が理解している限り、それは余分な辞書を持ち、それを update()
sで維持する代わりになります。
質問は次のとおりです。
ChainMap
はどのようなユースケースを対象としていますか?ChainMap
の実世界の例はありますか?ボーナス質問:Python2.xで使用する方法はありますか?
_Transforming Code into Beautiful, Idiomatic Python
_ で聞いたことがあるので、レイモンド・ヘッティンガーのPyConトークでツールキットに追加したいのですが、いつ使うべきか理解できません。
@ b4handの例が好きで、実際、過去のChainMapのような構造(ChainMap自体ではない)で、彼が言及した2つの目的に使用しました:多層構成のオーバーライドと、可変スタック/スコープエミュレーション。
Dict-updateループを使用するのと比較して、ChainMap
の他の2つの動機/利点/違いを指摘したいので、「最終」バージョンのみを保存します。
詳細:ChainMap構造は「階層化」されているため、次のような質問への回答をサポートしています。「デフォルト」値を取得していますか、それともオーバーライドされていますか?元の(「デフォルト」)値は何ですか?値はどのレベルでオーバーライドされましたか(@ b4handの構成例の借用:user-configまたはcommand-line-overrides)?簡単な辞書を使用すると、これらの質問に答えるために必要な情報はすでに失われています。
速度のトレードオフ:N
レイヤーがあり、それぞれに最大M
キーがあり、ChainMapの構築にはO(N)
および各ルックアップO(N)
最悪ケース[*]、更新ループを使用した辞書の作成にはO(NM)
および各ルックアップO(1)
が必要です。これは、頻繁に構築して毎回数回のルックアップのみを実行する場合、またはM
が大きい場合、ChainMapのレイジー構築アプローチが機能することを意味します。
[*](2)の分析では、実際には平均でO(1)
であり、最悪の場合O(1)
ですが、dict-accessはO(M)
であると想定しています。詳細を参照してください こちら 。
コマンドラインオプション、ユーザー設定ファイル、システム設定ファイルなど、複数の設定範囲がある設定オブジェクトにChainMap
を使用していることがわかりました。ルックアップはコンストラクター引数の順序で順序付けられるため、より低いスコープで設定をオーバーライドできます。個人的に使用したり、ChainMap
を使用したりしたことはありませんが、標準ライブラリへのかなり最近の追加であるため、驚くことではありません。
また、自分で字句スコープを実装しようとした場合、変数バインディングをプッシュおよびポップするスタックフレームをエミュレートするのにも役立ちます。
ChainMapの標準ライブラリドキュメント は、サードパーティライブラリの同様の実装へのいくつかの例とリンクを提供します。具体的には、Djangoの Contextクラス およびEnthoughtの MultiContextクラス と命名します。
私はこれでクラックを取るでしょう:
チェーンマップは、まさにそのような抽象化のように見えます。これは、非常に特殊な種類の問題に適したソリューションです。このユースケースを提案します。
あなたが持っている場合:
次に、チェーンマップを使用してマッピングのコレクションのビューを作成することを検討します。
しかし、これはすべて事後の正当化です。 Python人々は問題を抱えていて、コードのコンテキストで良い解決策を考え出した後、選択した場合に使用できるように解決策を抽象化するためにいくつかの追加作業を行いました。しかし、それがあなたの問題にふさわしいかどうかはあなた次第です。
不完全に答えるには:
ボーナス質問:Python2.xで使用する方法はありますか?
from ConfigParser import _Chainmap as ChainMap
ただし、これは実際のChainMap
ではなく、DictMixin
を継承し、以下を定義するだけであることに注意してください。
__init__(self, *maps)
__getitem__(self, key)
keys(self)
# And from DictMixin:
__iter__(self)
has_key(self, key)
__contains__(self, key)
iteritems(self)
iterkeys(self)
itervalues(self)
values(self)
items(self)
clear(self)
setdefault(self, key, default=None)
pop(self, key, *args)
popitem(self)
update(self, other=None, **kwargs)
get(self, key, default=None)
__repr__(self)
__cmp__(self, other)
__len__(self)
その実装も特に効率的ではないようです。