如何在一个表达式中合并两个词典?

python dictionary merge Yuki希 | 2020-02-02 19:35:06


我有两个Python字典,我想写一个ex按返回这两个字典,合并。如果返回结果而不是修改一个dict,那么我需要使用
update()
方法。
>>> x = {'a': 1, 'b': 2}
>>> y = {'b': 10, 'c': 11}
>>> z = x.update(y)
>>> print(z)
None
>>> x
{'a': 1, 'b': 10, 'c': 11}

如何在
z
中获得最终合并的dict,而不是
x

(更清楚的是,最后一个赢得了冲突处理
dict.update()
也是我要找的。)





30 答案



在一个罪恶的压迫中,两个Py8]iona是如何结合的?
蟒蛇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)

注意,这里讨论了一个建议(PEP 584),通过提供
dict
合并运算符,在未来的Python版本中进一步简化此操作,该运算符预计为
+
,这将允许:
z = x + y                       # pseudocode for now...

但这尚未实现。
解释
假设您有两个dict,并且希望将它们合并到新dict中而不更改原始dict:
x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}

所需的结果是得到一个合并了值的新字典(
z
),第二个dict的值覆盖了第一个dict的值。
>>> z
{'a': 1, 'b': 3, 'c': 4}

PEP 448中提出并在Python 3.5中可用的一个新语法是
z = {**x, **y}

,它实际上是一个表达式。
请注意,我们也可以使用文字符号进行合并:
z = {**x, 'foo': 1, 'bar': 2, **y}

现在:
>>> z
{'a': 1, 'b': 3, 'foo': 1, 'bar': 2, 'c': 4}

它现在显示为在3.5版的发布计划PEP 478中实现的,并且它现在已经进入了Python 3.5文档中的新内容。
但是,由于许多组织仍然使用Python 2,您可能希望以向后兼容的方式执行此操作。在Python 2和Python 3.0-3.4中,经典的Python方法是分两步进行的:
z = x.copy()
z.update(y) # which returns None since it mutates z

在这两种方法中,
y
将排在第二位,其值将替换
x
的值,因此,
'b'
将指向最终结果中的
3

还没有在Python 3.5上,但是如果还没有在python3.5上,或者需要编写向后兼容的代码,并且需要在单个表达式中使用这个表达式,最有效的方法是将其放入一个函数中:
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

此函数将在Python 2和Python 3中为所有dict工作。e、 g.给定指令
a
g

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

中的键值对优先于指令
a
f
,等等。
对其他答案的评论
不要使用以前接受的答案:
z = dict(x.items() + y.items())

在Python 2中,为每个dict在内存中创建两个列表,在内存中创建第三个列表,其长度等于前两个列表的长度,然后放弃所有三个列表以创建dict。在Python中3,这将失败,因为您将两个
dict_items
对象添加在一起,而不是两个列表-
>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
File "", line 1, in
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'

并且您必须显式地将它们创建为列表,例如
z = dict(list(x.items()) + list(y.items()))
。这是对资源和计算能力的浪费。
同样,当值是不可更改的对象(例如列表)时,在Python 3中合并
items()
viewitems()
在Python 2.7中)也会失败。即使您的值是散列的,因为集合在语义上是无序的,所以行为在优先级方面是未定义的。所以不要这样做:
>>> c = dict(a.items() | b.items())

这个例子演示了当值不可更改时会发生什么:
>>> x = {'a': []}
>>> y = {'b': []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
File "", line 1, in
TypeError: unhashable type: 'list'

下面是一个y应该优先的例子,但是,由于集合的任意顺序,x中的值将被保留:
>>> x = {'a': 2}
>>> y = {'a': 1}
>>> dict(x.items() | y.items())
{'a': 2}

另一种不应该使用的方法:
z = dict(x, **y)

这使用了
dict
构造函数,而且速度非常快而且内存效率很高(甚至比我们的两步过程稍微高一些),但是除非您确切地知道这里发生了什么(也就是说,第二个dict作为关键字参数传递给dict构造函数),否则很难读取,它不是预期的用法,所以它不是Pythonic。
下面是django中正在修正的用法的一个例子。
dict的目的是获取散列键(例如frozensets或tuples),但是当键不是字符串时,这个方法在Python3中失败。
>>> c = dict(a, **b)
Traceback (most recent call last):
File "", line 1, in
TypeError: keyword arguments must be strings

来自邮件列表,语言的创建者Guido van Rossum,写道:
我同意声明dict({},**{1:3})是非法的,因为这毕竟是滥用了
机制。

显然dict(x, **y)是在为“call
x.update(y)和return x”而“cool hack”。就我个人而言,我觉得这比“酷”更卑鄙。
我的理解(以及对语言创造者的理解)是,用于“pre>dict(**y)的目的是为了可读性而创建听写,e、 g.:
dict(a=1, b=10, c=11)

而不是
{'a': 1, 'b': 10, 'c': 11}

对注释的响应
不管Guido怎么说,
dict(x,**y)
都符合dict规范,该规范对Python 2和3都适用。这只适用于字符串键,这是关键字参数工作方式的直接结果,而不是dict的短期提交。在这里使用**运算符也不是滥用机制,事实上**正是为了将dict作为关键字传递而设计的。
同样,当键是非字符串时,它对3也不起作用。隐式调用约定是,名称空间采用普通的dict,而用户只能传递作为字符串的关键字参数。所有其他可调用的都强制执行它。
dict
打破了Python 2中的这种一致性:
>>> foo(**{('a', 'b'): None})
Traceback (most recent call last):
File "", line 1, in
TypeError: foo() keywords must be strings
>>> dict(**{('a', 'b'): None})
{('a', 'b'): None}

考虑到Python的其他实现(pypypy、Jython和IronPython),这种不一致性是不好的。因此它在Python 3中被修复了,因为这种用法可能是一个突破性的改变。
我向您提交,故意编写只在一种语言的一个版本中工作或只在给定某些任意约束的情况下工作的代码是恶意的无能。
更多注释:
dict(x.items() + y.items())
仍然是Python 2最可读的解决方案。可读性很重要。
我的回答是:
merge_two_dicts(x, y)
如果我们真的关心可读性的话,实际上对我来说似乎要清楚得多。而且它不支持前向兼容,因为Python2越来越被弃用。
{**x, **y}
似乎不处理嵌套字典。嵌套键的内容只是被覆盖,而不是合并[…]我最终被这些不递归合并的答案烧焦,我很惊讶没有人提到它。在我对“合并”这个词的解释中,这些答案描述了“用一个dict更新另一个dict”,而不是合并。我必须让你回到问题上来,这个问题要求两个字典的浅合并,第一个字典的值在一个表达式中被第二个字典的值覆盖。
假设两个字典,一个字典可以递归地将它们合并到一个函数中,但是你应该注意不要修改来自任何一个源的字典,而避免这种情况的最可靠方法是在赋值时生成copy。由于密钥必须是散列的,因此通常是不可变的,因此复制它们是没有意义的:
from copy import deepcopy
def dict_of_dicts_merge(x, y):
z = {}
overlapping_keys = x.keys() & y.keys()
for key in overlapping_keys:
z[key] = dict_of_dicts_merge(x[key], y[key])
for key in x.keys() - overlapping_keys:
z[key] = deepcopy(x[key])
for key in y.keys() - overlapping_keys:
z[key] = deepcopy(y[key])
return z

用法:
>>> x = {'a':{1:{}}, 'b': {2:{}}}
>>> y = {'b':{10:{}}, 'c': {11:{}}}
>>> dict_of_dicts_merge(x, y)
{'b': {2: {}, 10: {}}, 'a': {1: {}}, 'c': {11: {}}}

提出其他值类型的意外情况远远超出了这个问题的范围,因此,我将向您介绍我对“字典字典合并”这一典型问题的答案。
性能较低但正确的方法
这些方法性能较低,但它们将提供正确的行为。
它们的性能将远低于复制和更新或新的解包因为它们在更高的抽象级别上遍历每个键值对,但它们确实尊重优先顺序(后一个dict具有优先权)
您也可以在dict理解中手动链接dict:
{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7

或在python 2.6中(可能最早在引入生成器表达式时为2.4):
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

以下是在Python2.7(系统Python)中的Ubuntu14.04上完成的:
>>> 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

在Python3.5(死蛇PPA)中:
>>> 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文档
字典甚至更强大-由Brandon Rhodes在Pycon 2017上讲述
现代Python字典,伟大思想的汇合-由Raymond Hettinger在Pycon 2017上讲述

2020-02-02 19:35:18
杜庶仁

使用Python 3,只是有点复杂。创建

z

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

2020-02-02 19:35:18
ck


另一种选择:
z = x.copy()
z.update(y)

2020-02-02 19:35:18
网络上的虫子


另一个更简洁的选项:
z = dict(x, **y)

注意:这已经成为一个流行的答案,但必须指出的是,如果
y
有任何非字符串键,那么这实际上是滥用了CPython实现细节,并且在Python 3或pypypy、IronPython中都不起作用,或者Jython。而且,圭多也不是粉丝。因此,我不能推荐这种技术用于前向兼容或跨实现的可移植代码,这实际上意味着应该完全避免这种技术。

2020-02-02 19:35:18
⑨琪露诺


这可能不是一个流行的答案,但你几乎肯定不想这样做。如果你想要一个合并的副本,那么使用copy(或者deepcopy,取决于你想要什么),然后更新。这两行代码比用.items()+.items()创建的单行代码可读性强得多-更像Pythonic。显式优于隐式。
此外,当您使用.items()时(在Python 3.0之前),您将创建一个新列表,其中包含dict中的项。如果您的字典很大,则会产生相当大的开销(创建合并dict后,将立即丢弃两个大列表)。update()可以更有效地工作,因为它可以逐项运行第二个dict。
就时间而言:
>>> 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

IMO前两个之间的微小减速对于可读性来说是值得的。此外,字典创建的关键字参数只在Python2.3中添加,而copy()和update()在旧版本中有效。

2020-02-02 19:35:18


在后续的回答中,您询问了这两个备选方案的相对性能:
z1 = dict(x.items() + y.items())
z2 = dict(x, **y)

至少在我的机器上(运行Python 2.5.2的一个相当普通的x86ʂ64),备选方案不仅更短、更简单,而且速度更快。您可以使用Python附带的
timeit
模块来验证这一点。
示例1:相同的dict元组将20个连续整数映射到它们自己:
% 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
似乎总是走在前面。(如果同一测试的结果不一致,请尝试使用大于默认值3的数字传入
-r

示例2:非重叠字典将252个短字符串映射到整数,反之亦然:
% 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的倍数获胜。在我的书中那是一个相当大的胜利!
在比较了这两种方法之后,我想知道
z1
的性能差是否可以归因于构建两个项目列表的开销,这反过来让我想知道这种变化是否可以更好地工作:
from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))

一些快速测试,e、 g.
% 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

让我得出结论,
z3
z1
快一些,但速度不如
z2
快。当然不值得所有额外的输入。
这个讨论仍然缺少一些重要的东西,这就是将这些备选方案与合并两个列表的“明显”方式进行性能比较:使用
update
方法。为了使表达式与x或y保持一致,我将复制x而不是修改它,如下所示:
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
z2
的性能基本相同。你认为这可能是巧合吗?我不…
事实上,我甚至声称纯Python代码不可能做得比这更好。如果你能在C扩展模块中做得更好,我想Python的人很可能会对把你的代码(或者你的方法的变体)合并到Python核心中感兴趣。Python在很多地方都使用dict;优化它的操作是一件大事。
您也可以像Tony一样将其编写为
z0 = x.copy()
z0.update(y)

,但是(毫不奇怪)符号的不同对性能没有任何可测量的影响。用你觉得合适的。当然,他绝对正确地指出,两种说法的版本更容易理解。

2020-02-02 19:35:18
射命丸銀子


在Python 3.0及更高版本中,您可以使用
collections.ChainMap
将多个dict或其他映射组合在一起以创建单个可更新视图:
>>> 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

python3.5及更高版本的更新:您可以使用PEP 448扩展字典打包和解包。这是快速而简单的:
>>> x = {'a':1, 'b': 2}
>>> y = y = {'b':10, 'c': 11}
>>> {**x, **y}
{'a': 1, 'b': 10, 'c': 11}

2020-02-02 19:35:18
STaY


我想要类似的东西,但是有能力指定重复键上的值是如何合并的,所以我删掉了这个(但没有大量测试)。显然,这不是一个表达式,而是一个函数调用。
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

2020-02-02 19:35:18
爱丽丝·玛格特罗依德


递归/深度更新dict
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
演示:
code>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
}
}pre>

2020-02-02 19:35:18
羁绊


最好的版本是:
from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))

它比
dict(x.items() + y.items())
快,但不如
n = copy(a); n.update(b)
快,至少在CPython上是这样。如果您将由2to 3工具自动完成的
iteritems()
更改为
items()
,则此版本也适用于python3。
我个人最喜欢此版本,因为它在一个函数语法中描述了我所需要的相当好的内容。唯一的小问题是,从y开始的值优先于从x开始的值并不是很明显,但我不认为很难搞清楚

2020-02-02 19:35:18
666小能手


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}
br

2020-02-02 19:35:18
royhs


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

对于两个字典中都有键的项(“b”),您可以通过最后一个键来控制哪个键最终进入输出。

2020-02-02 19:35:18
magicml


虽然这个问题已经回答了好几次,但这个简单的问题解决方案还没有列出。
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z4 = {}
z4.update(x)
z4.update(y)

它和上面提到的z0和邪恶的z2一样快,但是很容易理解和改变。

2020-02-02 19:35:18
kaola


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

在这些阴暗而可疑的答案中,这个光辉的例子是将Python中的dicts合并的唯一好方法,它得到了独裁者Guido van Rossum本人的认可!其他人建议了一半,但没有将其放入函数中。
print dict_merge(
{'color':'red', 'model':'Mini'},
{'model':'Ferrari', 'owner':'Carl'})

给出:
{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}

2020-02-02 19:35:18
huoyan7733


如果你认为lambda是邪恶的,那么就不要再读下去了。
根据要求,你可以用一个表达式来编写快速且节省内存的解决方案:
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}

如前所述,使用两行代码或编写一个函数可能是更好的方法。

2020-02-02 19:35:18
戏言

像蟒蛇一样。使用理解:

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

2020-02-02 19:35:18
仙猫


在python3中,
items
方法不再返回列表,而是返回一个视图,它的作用类似于一个集合。在这种情况下,您需要使用set union,因为连接
+
将不起作用:
dict(x.items() | y.items())

对于2.7版中类似python3的行为,
viewitems
方法应该可以代替
items

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

我无论如何都喜欢这种表示法,因为将它看作是一个集合并集操作而不是连接操作(如标题所示)似乎更自然一些。
编辑:python 3的几个要点。首先,请注意,除非
y
中的键是字符串,否则
dict(x, **y)
技巧在python 3中不起作用。
此外,Raymond Hettinger的链表答案非常优雅,因为它可以将任意数量的dict作为参数,但从文档来看,它似乎是按顺序查找每个查找的所有指令列表:
查找连续搜索底层映射,直到找到一个键。
如果您的应用程序中有大量查找,则这可能会减慢您的查找速度:
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

因此查找速度要慢一个数量级。我是链图的粉丝,但在可能有很多查找的地方看起来不太实用。

2020-02-02 19:35:18
茶太


滥用导致马修的答案只有一个表达式:
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (lambda f=x.copy(): (f.update(y), f)lambda)()
>>> z
{'a': 1, 'c': 11, 'b': 10}

你说你想要一个表达式,所以我滥用
[1]
来绑定名称,并使用元组来覆盖lambda的一个表达式限制。如果你不想复制它,当然也可以这样做:
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (x.update(y), x)[1]
>>> z
{'a': 1, 'b': 10, 'c': 11}

2020-02-02 19:35:18
xiaoxiaobai


使用itertools保存顺序的简单解决方案(后面的命令优先)
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}

2020-02-02 19:35:18
雾花水月


两个字典的性能不好。参见https://mathieularosis.com/how-not-to-flatten-a-list-of-lists-in-python/

2020-02-02 19:35:18
乖猪猪


尽管答案对这个浅字典来说是好的,但这里定义的任何方法实际上都不会进行深字典合并。
示例如下:
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}}

如果是真正的合并,“one”条目应该在字典中有“depth_2”和“extra”作为条目。
使用chain也不起作用:
from itertools import chain
print dict(chain(a.iteritems(), b.iteritems()))

结果是:
{'two': True, 'one': {'extra': False}}

rcwesick给出的深度合并也会产生相同的结果。
是,合并示例词典是可行的,但没有一个是通用的合并机制。当我编写了一个真正合并的方法后,我将更新此内容。

2020-02-02 19:35:18
soulbadguy


根据这里和其他地方的想法,我理解了一个函数:
def merge(*dicts, **kv): 
return { k:v for d in list(dicts) + [kv] for k,v in d.items() }

用法(在python 3中测试):
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})

您可以使用lambda代替

2020-02-02 19:35:18
佚闲


迄今为止,我在列出的解决方案中遇到的问题是,在合并字典中,键“b”的值是10,但按照我的思维方式,它应该是12。
因此,我给出了以下结果:
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}

2020-02-02 19:35:18
黑音大魔王


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

这可以解决您的问题。

2020-02-02 19:35:18
32167


(仅适用于Python2.7*;Python3*有更简单的解决方案)
如果您不反对导入标准库模块,您可以在成功时执行
from functools import reduce
def merge_dicts(*dicts):
return reduce(lambda a, d: a.update(d) or a, dicts, {})

(需要
or a
位,因为
dict.update
总是返回
None

2020-02-02 19:35:18
CH.


这可以通过一个简单的听写理解来完成:
>>> 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)
}

在我看来,“单一表达式”部分的最佳答案是不需要额外的函数,而且它很短。

2020-02-02 19:35:18
鱼罐头


>>> 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}

2020-02-02 19:35:18
茶茶子


太傻了,
.update
什么都不返回。
我只是使用一个简单的助手函数来解决问题:
def merge(dict1,*dicts):
for dict2 in dicts:
dict1.update(dict2)
return dict1

示例:
merge(dict1,dict2)
merge(dict1,dict2,dict3)
merge(dict1,dict2,dict3,dict4)
merge({},dict1,dict2) # this one returns a new copy

2020-02-02 19:35:18
f2


如果您不介意变异
x

x.update(y) or x

简单、可读、性能ormant。您知道
update()
总是返回
None
,这是一个错误值。因此,在更新后,上述ex键的计算结果将始终为
x

标准库中的变异方法(如
.update()
)按惯例返回
None
,因此此模式也适用于那些。如果您使用的方法不遵循此约定,则
可能无法工作。但是,您可以使用元组显示和索引使其成为单个表达式。无论第一个元素的计算结果是什么,这都可以工作。
(x.update(y), x)[-1]

如果变量中还没有x,则可以使用
lambda
在不使用赋值语句的情况下生成局部变量。这相当于使用let表达式,这在函数语言中是一种常见的技术,但可能是不通俗的。
(lambda x: x.update(y) or x)({'a': 1, 'b': 2})

尽管它与下面使用的新的海象运算符(仅限Python 3.8+)没有太大区别:如果您确实需要副本,请使用
(x := {'a': 1, 'b': 2}).update(y) or x

,PEP 448样式最简单。但是,如果您的(旧的)Python版本中没有这种模式,let模式也可以在这里工作。
(lambda z: z.update(y) or z)(x.copy())

(当然,这相当于
(z := x.copy()).update(y) or z
,但是如果您的Python版本足够新,那么PEP 448样式将可用。)

2020-02-02 19:35:18
我超爱萌娘


使用听写理解,您可以
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}

if elsepre>pre>code>

2020-02-02 19:35:18
冰凌樱雨


World is powered by solitude
备案号:湘ICP备19012068号