web-dev-qa-db-ja.com

dictの理解におけるdictのマージ

python 3.5では、ダブルスプラットアンパックを使用してdictをマージできます

_>>> d1 = {1: 'one', 2: 'two'}
>>> d2 = {3: 'three'}
>>> {**d1, **d2}
{1: 'one', 2: 'two', 3: 'three'}
_

涼しい。ただし、動的なユースケースに一般化されているようには見えません。

_>>> ds = [d1, d2]
>>> {**d for d in ds}
SyntaxError: dict unpacking cannot be used in dict comprehension
_

代わりに、reduce(lambda x,y: {**x, **y}, ds, {})を実行する必要がありますが、これは非常に醜いようです。その表現にあいまいさがないように見えるのに、なぜ「それを行うための1つの明白な方法」がパーサーによって許可されないのですか?

21
wim

それはあなたの質問に対する正確な答えではありませんが、 ChainMap を使用して、あなたが提案することを行うための慣用的でエレガントな方法であると考えます(辞書をインラインでマージします):

>>> d1 = {1: 'one', 2: 'two'}
>>> d2 = {3: 'three'}
>>> ds = [d1, d2]
>>> dict(ChainMap(*ds))
{1: 'one', 2: 'two', 3: 'three'}

これは特に透過的なソリューションではありませんが、多くのプログラマーはChainMapがどのように機能するかを正確に知らない可能性があるためです。 (@AnttiHaapalaが指摘しているように)「最初に見つかったものが使用される」ことに注意してください。したがって、意図によっては、reversedsをdictに渡す前にChainMapを呼び出す必要がある場合があります。

>>> d2 = {3: 'three', 2:'LOL'}
>>> dict(ChainMap(*ds))
{1: 'one', 2: 'two', 3: 'three'}

>>> dict(ChainMap(*reversed(ds)))
{1: 'one', 2: 'LOL', 3: 'three'}
14

私にとって、明白な方法は次のとおりです。

d_out = {}
for d in ds:
    d_out.update(d)

これは迅速で、おそらく非常にパフォーマンスが高いです。 python開発者のために話すことができるかどうかはわかりませんが、期待されるバージョンがより読みやすいかどうかはわかりません。たとえば、理解度はセットのように見えます- :がないため、私には理解できません。FWIW、技術的理由(パーサーのあいまいさなど)がないその形式の理解の開梱を追加できませんでした

どうやら、 これらのフォームが提案されました ですが、(まだ)それらを実装することを保証するのに十分な普遍的なサポートがありませんでした。

8
mgilson
final = {}
for data in [d1, d2]:
    final = {**final,**data}
1
James Huckle