Posted at

pythonで2つの辞書をマージした辞書を作る

More than 1 year has passed since last update.


お題

2つの辞書d1, d2があるとき、以下の関数のようなものを簡単に書けないか?

def foo(d1, d2):

d3 = dict(d1)
d3.update(d2)
return d3


解答

python3.5以降なら、以下の式で良い。

{**d1, **d2}


解説

辞書表記に**辞書(辞書アンパッキング)を渡すのは


A double asterisk ** denotes dictionary unpacking. Its operand must be a mapping. Each mapping item is added to the new dictionary. Later values replace values already set by earlier key/datum pairs and earlier dictionary unpackings.


( http://docs.python.jp/3.6/reference/expressions.html#dictionary-displays より )

つまり



  • **で渡された辞書のアイテムが新しい辞書のアイテムになる

  • アイテムは後勝ち

ということで所望の動作となります。


補足

辞書アンパッキングは関数の引数にもあるので、dict()コンストラクタを使って

dict(**d1, **d2)

でもできそうに見えますが、以下の二点でダメです。


キーが重複するとダメ


キーが重複

dict(**{'a': 0}, **{'a': 1})



結果

Traceback (most recent call last):

File "<stdin>", line 1, in <module>
TypeError: type object got multiple values for keyword argument 'a'

これは


If the syntax **expression appears in the function call, expression must evaluate to a mapping, the contents of which are treated as additional keyword arguments. If a keyword is already present (as an explicit keyword argument, or from another unpacking), a TypeError exception is raised.


( http://docs.python.jp/3.6/reference/expressions.html#calls より )

のためです。


キーが文字列じゃないとダメ


キーが文字列でない

dict(**{0: 0})



結果

Traceback (most recent call last):

File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings

これは、引数リストの辞書アンパックはキーワード引数になるからです。

キーワード引数である以上、キーは文字列でなければなりません。


参考リンク

How to merge two dictionaries in a single expression? (stackoverflow)

いろいろ調べたり試したりしたことは殆どここに載っていました。