web-dev-qa-db-ja.com

collections.ChainMapの目的は何ですか?

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の実世界の例はありますか?
  • Python3に切り替えたサードパーティライブラリで使用されていますか?

ボーナス質問:Python2.xで使用する方法はありますか?


_Transforming Code into Beautiful, Idiomatic Python_ で聞いたことがあるので、レイモンド・ヘッティンガーのPyConトークでツールキットに追加したいのですが、いつ使うべきか理解できません。

59
alecxe

@ b4handの例が好きで、実際、過去のChainMapのような構造(ChainMap自体ではない)で、彼が言及した2つの目的に使用しました:多層構成のオーバーライドと、可変スタック/スコープエミュレーション。

Dict-updateループを使用するのと比較して、ChainMapの他の2つの動機/利点/違いを指摘したいので、「最終」バージョンのみを保存します。

  1. 詳細:ChainMap構造は「階層化」されているため、次のような質問への回答をサポートしています。「デフォルト」値を取得していますか、それともオーバーライドされていますか?元の(「デフォルト」)値は何ですか?値はどのレベルでオーバーライドされましたか(@ b4handの構成例の借用:user-configまたはcommand-line-overrides)?簡単な辞書を使用すると、これらの質問に答えるために必要な情報はすでに失われています。

  2. 速度のトレードオフ:Nレイヤーがあり、それぞれに最大Mキーがあり、ChainMapの構築にはO(N)および各ルックアップO(N)最悪ケース[*]、更新ループを使用した辞書の作成にはO(NM)および各ルックアップO(1)が必要です。これは、頻繁に構築して毎回数回のルックアップのみを実行する場合、またはMが大きい場合、ChainMapのレイジー構築アプローチが機能することを意味します。

[*](2)の分析では、実際には平均でO(1)であり、最悪の場合O(1)ですが、dict-accessはO(M)であると想定しています。詳細を参照してください こちら

59
shx2

コマンドラインオプション、ユーザー設定ファイル、システム設定ファイルなど、複数の設定範囲がある設定オブジェクトにChainMapを使用していることがわかりました。ルックアップはコンストラクター引数の順序で順序付けられるため、より低いスコープで設定をオーバーライドできます。個人的に使用したり、ChainMapを使用したりしたことはありませんが、標準ライブラリへのかなり最近の追加であるため、驚くことではありません。

また、自分で字句スコープを実装しようとした場合、変数バインディングをプッシュおよびポップするスタックフレームをエミュレートするのにも役立ちます。

ChainMapの標準ライブラリドキュメント は、サードパーティライブラリの同様の実装へのいくつかの例とリンクを提供します。具体的には、Djangoの Contextクラス およびEnthoughtの MultiContextクラス と命名します。

36
b4hand

私はこれでクラックを取るでしょう:

チェーンマップは、まさにそのような抽象化のように見えます。これは、非常に特殊な種類の問題に適したソリューションです。このユースケースを提案します。

あなたが持っている場合:

  1. 複数のマッピング(例、辞書)
  2. それらのマッピングでのキーの重複
  3. 「最高優先度」マッピングのキーの値にアクセスしたい消費アプリケーション。特定のキーのすべてのマッピングの全体的な順序付けがあります(つまり、マッピングの優先度は等しいが、それらのマッピング内にキーの重複はありません)(Pythonアプリケーションでは、パッケージは同じディレクトリに置くことができます(同じ優先順位)が、異なる名前を持つ必要があるため、定義により、シンボル名そのディレクトリ内で重複することはできません。)
  4. 消費アプリケーションはキーの値を変更する必要はありません
  5. 同時に、マッピングは独立したIDを維持する必要があり、外力によって非同期に変更できます
  6. また、マッピングは十分に大きく、アクセスするのに十分高価であるか、アプリケーションアクセス間で頻繁に変更されるため、アプリが必要とするたびに投影を計算するコスト(3)は、アプリケーションのパフォーマンスの重要な懸念事項です...

次に、チェーンマップを使用してマッピングのコレクションのビューを作成することを検討します。

しかし、これはすべて事後の正当化です。 Python人々は問題を抱えていて、コードのコンテキストで良い解決策を考え出した後、選択した場合に使用できるように解決策を抽象化するためにいくつかの追加作業を行いました。しかし、それがあなたの問題にふさわしいかどうかはあなた次第です。

6
BobHy

不完全に答えるには:

ボーナス質問: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)

その実装も特に効率的ではないようです。

5
A T