# 如何在一个expression式中合并两个字典？

` `>>> x = {'a':1, 'b': 2} >>> y = {'b':10, 'c': 11} >>> z = x.update(y) >>> print(z) None >>> x {'a': 1, 'b': 10, 'c': 11}` `

（为了更加清楚， `dict.update()`的最后一个冲突处理也是我正在寻找的。）

# 我怎样才能在一个expression式中合并两个Python字典？

• 在Python 3.5或更高版本中，：

` `z = {**x, **y}` `
• 在Python 2中，（或者3.4或者更低）写一个函数：

` `def merge_two_dicts(x, y): z = x.copy() # start with x's keys and values z.update(y) # modifies z with y's keys and values & returns None return z` `

` `z = merge_two_dicts(x, y)` `

## 说明

` `x = {'a': 1, 'b': 2} y = {'b': 3, 'c': 4}` `

` `>>> z {'a': 1, 'b': 3, 'c': 4}` `

PEP 448中提出了一个新的语法， 可以从Python 3.5中获得

` `z = {**x, **y}` `

` `z = x.copy() z.update(y) # which returns None since it mutates z` `

# 还没有在Python 3.5上，但想要一个expression式

` `def merge_two_dicts(x, y): """Given two dicts, merge them into a new dict as a shallow copy.""" z = x.copy() z.update(y) return z` `

` `z = merge_two_dicts(x, y)` `

` `def merge_dicts(*dict_args): """ Given any number of dicts, shallow copy and merge into a new dict, precedence goes to key value pairs in latter dicts. """ result = {} for dictionary in dict_args: result.update(dictionary) return result` `

` `z = merge_dicts(a, b, c, d, e, f, g)` `

# 对其他答案的批评

` `z = dict(x.items() + y.items())` `

` `>>> c = dict(a.items() + b.items()) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'` `

` `>>> c = dict(a.items() | b.items())` `

` `>>> x = {'a': []} >>> y = {'b': []} >>> dict(x.items() | y.items()) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list'` `

` `>>> x = {'a': 2} >>> y = {'a': 1} >>> dict(x.items() | y.items()) {'a': 2}` `

` `z = dict(x, **y)` `

` `>>> c = dict(a, **b) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: keyword arguments must be strings` `

` `dict(a=1, b=10, c=11)` `

` `{'a': 1, 'b': 10, 'c': 11}` `

## 回应评论

` `>>> foo(**{('a', 'b'): None}) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: foo() keywords must be strings >>> dict(**{('a', 'b'): None}) {('a', 'b'): None}` `

Python的其他实现（Pypy，Jython，IronPython）导致了这种不一致。 因此它在Python 3中被修复，因为这个用法可能是一个突破性的改变。

`dict(x.items() + y.items())`仍然是Python 2最可读的解决scheme。可读性计数。

# 性能较差，但正确的临时性

` `{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7` `

` `dict((k, v) for d in dicts for k, v in d.items())` `

`itertools.chain`会按照正确的顺序将迭代器链接到键值对上：

` `import itertools z = dict(itertools.chain(x.iteritems(), y.iteritems()))` `

# 性能分析

` `import timeit` `

` `>>> min(timeit.repeat(lambda: merge_two_dicts(x, y))) 0.5726828575134277 >>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} )) 1.163769006729126 >>> min(timeit.repeat(lambda: dict(itertools.chain(x.iteritems(), y.iteritems())))) 1.1614501476287842 >>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items()))) 2.2345519065856934` `

` `>>> min(timeit.repeat(lambda: {**x, **y})) 0.4094954460160807 >>> min(timeit.repeat(lambda: merge_two_dicts(x, y))) 0.7881555100320838 >>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} )) 1.4525277839857154 >>> min(timeit.repeat(lambda: dict(itertools.chain(x.items(), y.items())))) 2.3143140770262107 >>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items()))) 3.2069112799945287` `

## 词典资源

• 我对Python的字典实现的解释，更新为3.6。
• 回答如何将新密钥添加到字典中
• 将两个列表映射到一个字典中
• 官方Python 文档的字典
• 词典甚至更强大 – 在2017年Pycon上Brandon Rhodes的谈话
• 现代Python词典，一个伟大想法的汇合 – Raymond Hettinger在Pycon 2017上的发言

` `z = dict(x.items() + y.items())` `

` `>>> x = {'a':1, 'b': 2} >>> y = {'b':10, 'c': 11} >>> z = dict(x.items() + y.items()) >>> z {'a': 1, 'c': 11, 'b': 10}` `

` `>>> z = dict(list(x.items()) + list(y.items())) >>> z {'a': 1, 'c': 11, 'b': 10}` `

` `z = x.copy() z.update(y)` `

` `z = dict(x, **y)` `

` `>>> timeit.Timer("dict(x, **y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000) 15.52571702003479 >>> timeit.Timer("temp = x.copy()\ntemp.update(y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000) 15.694622993469238 >>> timeit.Timer("dict(x.items() + y.items())", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000) 41.484580039978027` `

` `z1 = dict(x.items() + y.items()) z2 = dict(x, **y)` `

` `% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z1=dict(x.items() + y.items())' 100000 loops, best of 3: 5.67 usec per loop % python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z2=dict(x, **y)' 100000 loops, best of 3: 1.53 usec per loop` `

`z2`赢得3.5倍左右。 不同的字典似乎有不同的结果，但`z2`似乎总是出来。 （如果在相同的testing中得到不一致的结果，请尝试将大于默认值3的数字传入`-r` 。）

` `% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z1=dict(x.items() + y.items())' 1000 loops, best of 3: 260 usec per loop % python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z2=dict(x, **y)' 10000 loops, best of 3: 26.9 usec per loop` `

`z2`大约是10倍。这是我的书中一个非常大的胜利！

` `from itertools import chain z3 = dict(chain(x.iteritems(), y.iteritems()))` `

` `% python -m timeit -s 'from itertools import chain; from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z3=dict(chain(x.iteritems(), y.iteritems()))' 10000 loops, best of 3: 66 usec per loop` `

` `z0 = dict(x) z0.update(y)` `

` `% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z0=dict(x); z0.update(y)' 10000 loops, best of 3: 26.9 usec per loop` `

` `z0 = x.copy() z0.update(y)` `

` `def merge(d1, d2, merge_fn=lambda x,y:y): """ Merges two dictionaries, non-destructively, combining values on duplicate keys as defined by the optional merge function. The default behavior replaces the values in d1 with corresponding values in d2. (There is no other generally applicable merge strategy, but often you'll have homogeneous types in your dicts, so specifying a merge technique can be valuable.) Examples: >>> d1 {'a': 1, 'c': 3, 'b': 2} >>> merge(d1, d1) {'a': 1, 'c': 3, 'b': 2} >>> merge(d1, d1, lambda x,y: x+y) {'a': 2, 'c': 6, 'b': 4} """ result = dict(d1) for k,v in d2.iteritems(): if k in result: result[k] = merge_fn(result[k], v) else: result[k] = v return result` `

` `>>> 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 b --> 10 c --> 11` `

` `from itertools import chain x = {'a':1, 'b': 2} y = {'b':10, 'c': 11} dict(chain(x.iteritems(), y.iteritems()))` `

# recursion/深度更新字典

` `def deepupdate(original, update): """ Recursively update a dict. Subdict's won't be overwritten but also updated. """ for key, value in original.iteritems(): if key not in update: update[key] = value elif isinstance(value, dict): deepupdate(value, update[key]) return update` `

` `pluto_original = { 'name': 'Pluto', 'details': { 'tail': True, 'color': 'orange' } } pluto_update = { 'name': 'Pluutoo', 'details': { 'color': 'blue' } } print deepupdate(pluto_original, pluto_update)` `

` `{ 'name': 'Pluutoo', 'details': { 'color': 'blue', 'tail': True } }` `

` `x = {'a':1, 'b': 2} y = {'b':10, 'c': 11} z = dict(x.items() + y.items()) print z` `

Python 3.5（PEP 448）允许更好的语法选项：

` `x = {'a': 1, 'b': 1} y = {'a': 2, 'c': 2} final = {**x, **y} final # {'a': 2, 'b': 1, 'c': 2}` `

` `final = {'a': 1, 'b': 1, **x, **y}` `

` `x = {'a':1, 'b': 2} y = {'b':10, 'c': 11} z4 = {} z4.update(x) z4.update(y)` `

` `def dict_merge(a, b): c = a.copy() c.update(b) return c new = dict_merge(old, extras)` `

` `print dict_merge( {'color':'red', 'model':'Mini'}, {'model':'Ferrari', 'owner':'Carl'})` `

` `{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}` `

` `x = {'a':1, 'b':2} y = {'b':10, 'c':11} z = (lambda a, b: (lambda a_copy: a_copy.update(b) or a_copy)(a.copy()))(x, y) print z {'a': 1, 'c': 11, 'b': 10} print x {'a': 1, 'b': 2}` `

` `dict(x.items() | y.items())` `

` `dict(x.viewitems() | y.viewitems())` `

` `In [1]: from collections import ChainMap In [2]: from string import ascii_uppercase as up, ascii_lowercase as lo; x = dict(zip(lo, up)); y = dict(zip(up, lo)) In [3]: chainmap_dict = ChainMap(y, x) In [4]: union_dict = dict(x.items() | y.items()) In [5]: timeit for k in union_dict: union_dict[k] 100000 loops, best of 3: 2.15 µs per loop In [6]: timeit for k in chainmap_dict: chainmap_dict[k] 10000 loops, best of 3: 27.1 µs per loop` `

` `>>> x = {'a':1, 'b': 2} >>> y = {'b':10, 'c': 11} >>> z = (lambda f=x.copy(): (f.update(y), f)[1])() >>> z {'a': 1, 'c': 11, 'b': 10}` `

` `>>> x = {'a':1, 'b': 2} >>> y = {'b':10, 'c': 11} >>> z = (x.update(y), x)[1] >>> z {'a': 1, 'b': 10, 'c': 11}` `

pythonic。 使用理解 ：

` `z={i:d[i] for d in [x,y] for i in d} >>> print z {'a': 1, 'c': 11, 'b': 10}` `

` `import itertools as it merge = lambda *args: dict(it.chain.from_iterable(it.imap(dict.iteritems, args)))` `

` `>>> x = {'a':1, 'b': 2} >>> y = {'b':10, 'c': 11} >>> merge(x, y) {'a': 1, 'b': 10, 'c': 11} >>> z = {'c': 3, 'd': 4} >>> merge(x, y, z) {'a': 1, 'b': 10, 'c': 3, 'd': 4}` `

` `a = { 'one': { 'depth_2': True }, 'two': True } b = { 'one': { 'extra': False } } print dict(a.items() + b.items())` `

` `{ 'one': { 'extra': False', 'depth_2': True }, 'two': True }` `

` `{'two': True, 'one': {'extra': False}}` `

` `from itertools import chain print dict(chain(a.iteritems(), b.iteritems()))` `

` `{'two': True, 'one': {'extra': False}}` `

rcwesick给的深度合并也创造了同样的结果。

` `def union2(dict1, dict2): return dict(list(dict1.items()) + list(dict2.items()))` `

n词典

` `def union(*dicts): return dict(itertools.chain.from_iterable(dct.items() for dct in dicts))` `

`sum`有不好的performance。 请参阅https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/

` `>>> x = {'a':1, 'b': 2} >>> y = {'b':10, 'c': 11} >>> x, z = dict(x), x.update(y) or x >>> x {'a': 1, 'b': 2} >>> y {'c': 11, 'b': 10} >>> z {'a': 1, 'c': 11, 'b': 10}` `

` `def merge(*dicts, **kv): return { k:v for d in list(dicts) + [kv] for k,v in d.items() }` `

` `assert (merge({1:11,'a':'aaa'},{1:99, 'b':'bbb'},foo='bar')==\ {1: 99, 'foo': 'bar', 'b': 'bbb', 'a': 'aaa'}) assert (merge(foo='bar')=={'foo': 'bar'}) assert (merge({1:11},{1:99},foo='bar',baz='quux')==\ {1: 99, 'foo': 'bar', 'baz':'quux'}) assert (merge({1:11},{1:99})=={1: 99})` `

` `import timeit n=100000 su = """ x = {'a':1, 'b': 2} y = {'b':10, 'c': 11} """ def timeMerge(f,su,niter): print "{:4f} sec for: {:30s}".format(timeit.Timer(f,setup=su).timeit(n),f) timeMerge("dict(x, **y)",su,n) timeMerge("x.update(y)",su,n) timeMerge("dict(x.items() + y.items())",su,n) timeMerge("for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k] ",su,n) #confirm for loop adds b entries together x = {'a':1, 'b': 2} y = {'b':10, 'c': 11} for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k] print "confirm b elements are added:",x` `

# 结果：

` `0.049465 sec for: dict(x, **y) 0.033729 sec for: x.update(y) 0.150380 sec for: dict(x.items() + y.items()) 0.083120 sec for: for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k] confirm b elements are added: {'a': 1, 'c': 11, 'b': 12}` `

` `x = {'a':1, 'b': 2} y = {'b':10, 'c': 11} z = dict(x.items()+y.items()) print(z)` `

` `x = {'a':1, 'b': 2} y = {'b':10, 'c': 11} z = dict(x.items()|y.items()) print(z)` `

` `import collections a = {1: 1, 2: 2} b = {2: 3, 3: 4} c = {3: 5} r = dict(collections.ChainMap(a, b, c)) print(r)` `

date：

` `{1: 1, 2: 2, 3: 4}` `

` `x = {'a':1, 'b': 2} y = {'b':10, 'c': 11} dc = {xi:(x[xi] if xi not in list(y.keys()) else y[xi]) for xi in list(x.keys())+(list(y.keys()))}` `

` `>>> dc {'a': 1, 'c': 11, 'b': 10}` `

` `{ (some_key if condition else default_key):(something_if_true if condition else something_if_false) for key, value in dict_.items() }` `

` `>>> x = {'a':1, 'b': 2} >>> y = {'b':10, 'c': 11} >>> { key: y[key] if key in y else x[key] for key in set(x) + set(y) }` `

` `from collections import Counter dict1 = {'a':1, 'b': 2} dict2 = {'b':10, 'c': 11} result = dict(Counter(dict1) + Counter(dict2))` `