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

时间:2008-09-02 07:44:30

标签: python dictionary merge

我有两个Python词典,我想编写一个返回这两个词典的表达式,合并。 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而不是x中获得最终合并的字典?

(要清楚的是,dict.update()的最后一次胜利冲突处理也是我正在寻找的。)

49 个答案:

答案 0 :(得分:4445)

  

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

对于词典xyz成为一个浅层合并的词典,y的值替换x中的值。

  • 在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)
    

解释

假设您有两个dicts,并且想要将它们合并到一个新的dict而不改变原始的dicts:

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

期望的结果是获得一个新的字典(z),其值合并,第二个字典的值覆盖第一个字典。

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

PEP 448available as of Python 3.5中提出的新语法是

z = {**x, **y}

这确实是一个单一的表达方式。

请注意,我们也可以使用文字符号合并:

z = {**x, 'foo': 1, 'bar': 2, **y}

现在:

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

它现在显示为release schedule for 3.5, PEP 478中的实现,现在它已进入What's New in Python 3.5文档。

但是,由于许多组织仍在使用Python 2,因此您可能希望以向后兼容的方式执行此操作。 Python 2和Python 3.0-3.4中提供的经典Pythonic方法是通过两个步骤完成的:

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

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

尚不在Python 3.5上,但需要单个表达式

如果您尚未使用Python 3.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)

您还可以创建一个函数来合并未定义数量的dicts,从零到非常大的数字:

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

此功能适用于所有dicts的Python 2和3。例如给出了ag的词汇:

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

g中的键值对优先于dicts af,依此类推。

对其他答案的批评

不要使用你在之前接受的答案中看到的内容:

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 "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'

并且你必须明确地将它们创建为列表,例如z = dict(list(x.items()) + list(y.items()))。这是浪费资源和计算能力。

同样,当值为不可用对象(例如列表)时,在Python 3中使用items()(在Python 2.7中为viewitems())的并集也会失败。即使您的值是可清除的,因为集合在语义上是无序的,所以行为在优先级方面是未定义的。所以不要这样做:

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

这里有一个例子,其中y应该具有优先权,但是由于任意顺序的集合而保留x中的值:

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

你不应该使用的另一个黑客:

z = dict(x, **y)

这使用dict构造函数,并且速度非常快且内存效率高(甚至比我们的两步过程稍微多一点)但是除非你确切知道这里发生了什么(也就是说,第二个字典是作为关键字参数传递给dict构造函数),它难以阅读,它不是预期的用法,因此它不是Pythonic。

以下是remediated in django的使用示例。

Dicts旨在获取可散列密钥(例如frozensets或tuples),但当密钥不是字符串时,此方法在Python 3中失败。

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

来自mailing list的语言创建者Guido van Rossum写道:

  

我很好   宣布dict({},** {1:3})是非法的,因为它毕竟是滥用   **机制。

  

显然dict(x,** y)正在四处走动&#34;酷hack&#34;为&#34;打电话   x.update(y)并返回x&#34;。就个人而言,我发现它比它更卑鄙   凉爽。

我的理解(以及对creator of the language的理解)dict(**y)的预期用途是为了可读性目的而创建dicts,例如:

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

而不是

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

对评论的回应

  

尽管Guido说,dict(x, **y)符合dict规范,但顺便说一下。适用于Python 2和3.事实上,这仅适用于字符串键,这是关键字参数如何工作而不是dict短路的直接结果。在这个地方也没有使用**运算符滥用该机制,事实上**被精确地设计为将dicts作为关键字传递。

同样,当密钥是非字符串时,它不适用于3。隐式调用契约是命名空间采用普通的dicts,而用户只能传递字符串的关键字参数。所有其他callables强制执行它。 dict在Python 2中破坏了这种一致性:

>>> 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最易读的解决方案。可读性很重要。

我的回答:merge_two_dicts(x, y)实际上对我来说更清楚,如果我们真的关心可读性的话。并且它不向前兼容,因为Python 2越来越被弃用。

  

{**x, **y}似乎没有处理嵌套字典。嵌套键的内容被简单地覆盖,没有合并[...]我最终被这些没有递归合并的答案所灼烧,我很惊讶没有人提到它。在我对'&34;合并&#34;这个词的解释中这些答案描述&#34;用另一个&#34;更新一个字典,而不是合并。

是。我必须回过头来回答一个问题,即要求 两个 词典的合并,第一个值是被第二个覆盖 - 用一个表达式覆盖。

假设有两个字典字典,可以在一个函数中递归地合并它们,但是你应该注意不要从任何一个源修改dicts,并且最可靠的方法是在分配值时复制它们。因为密钥必须是可以清洗的,因此通常是不可变的,所以复制它们是没有意义的:

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

提出其他价值类型的突发事件远远超出了这个问题的范围,所以我会指出my answer to the canonical question on a "Dictionaries of dictionaries merge"

性能较差但正确的Ad-hocs

这些方法性能较差,但它们会提供正确的行为。 与copyupdate或新的解包相比,它们更少性能,因为它们在更高的抽象级别迭代每个键值对,但它们 尊重优先顺序(后面的dicts优先)

你也可以在字典理解中手动链接dicts:

{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

以下是在Ubuntu 14.04上完成的

在Python 2.7(系统Python)中:

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

在Python 3.5(deadsnakes 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

词典上的资源

答案 1 :(得分:1524)

在您的情况下,您可以做的是:

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

这将根据您的需要将最终字典放在z中,并使键b的值被第二个(y)字典的值正确覆盖:< / p>

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

如果你使用Python 3,它只是稍微复杂一点。要创建z

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

答案 2 :(得分:589)

替代方案:

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

答案 3 :(得分:301)

另一个更简洁的选择:

z = dict(x, **y)

注意:这已经成为一个受欢迎的答案,但重要的是要指出,如果y有任何非字符串键,那么这种情况根本就是滥用一个CPython实现细节,它在Python 3或PyPy,IronPython或Jython中不起作用。另外,Guido is not a fan。所以我不推荐这种技术用于前向兼容或交叉实现的可移植代码,这实际上意味着它应该完全避免。

答案 4 :(得分:184)

这可能不是一个受欢迎的答案,但你几乎肯定不想这样做。如果您想要一个合并的副本,那么请使用副本(或deepcopy,具体取决于您的需要),然后进行更新。这两行代码比使用.items()+ .items()的单行创建更具可读性 - 更多Pythonic。明确比隐含更好。

此外,当您使用.items()(Python 3.0之前)时,您正在创建一个包含dict项目的新列表。如果你的词典很大,那么这就是很多开销(一旦创建合并的dict就会抛弃两个大的列表)。 update()可以更有效地工作,因为它可以逐项运行第二个dict。

time而言:

>>> 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前两者之间的微小减速对于可读性而言是值得的。此外,字典创建的关键字参数仅在Python 2.3中添加,而copy()和update()将在旧版本中使用。

答案 5 :(得分:130)

在后续回答中,您询问了这两种选择的相对表现:

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

在我的机器上,至少(相当普通的x86_64运行Python 2.5.2),替代z2不仅更短更简单,而且速度更快。您可以使用Python附带的timeit模块自行验证。

示例1:将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()))

一些快速测试,例如

% 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

让我得出结论:z3z1略快,但不如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

换句话说,z0z2似乎具有基本相同的效果。你认为这可能是巧合吗?我没有......

事实上,我甚至声称纯Python代码不可能比这更好。如果你可以在C扩展模块中做得更好,我想Python人员可能会对将你的代码(或你的方法的变体)合并到Python核心感兴趣。 Python在很多地方使用dict;优化其运营是一件大事。

您也可以将其写为

z0 = x.copy()
z0.update(y)
正如托尼所做的那样,但(并不奇怪)记谱法的差异原来并没有对绩效产生任何可衡量的影响。使用适合您的任何一种。当然,他指出双语句版本更容易理解是完全正确的。

答案 6 :(得分:95)

我想要类似的东西,但能够指定重复键的值是如何合并的,所以我将其破解(但没有对它进行大量测试)。显然这不是单个表达式,而是单个函数调用。

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

答案 7 :(得分:89)

在Python 3中,您可以使用collections.ChainMap将多个dicts或其他映射组合在一起以创建单个可更新视图:

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

答案 8 :(得分:69)

递归/深度更新字典

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

感谢rednaw进行编辑。

答案 9 :(得分:60)

不使用副本时我能想到的最佳版本是:

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上如此。如果您将iteritems()更改为items(),此版本也适用于Python 3,这是由2to3工具自动完成的。

就个人而言,我最喜欢这个版本,因为它在单一功能语法中描述了我想要的东西。唯一的小问题是,y的值优先于x的值,但并不是很明显,但我不认为很难弄明白。

答案 10 :(得分:49)

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}

答案 11 :(得分:49)

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

对于两个词典中都带有键的项目('b'),您可以通过将最后一个词放在最后来控制输出中的哪一个。

答案 12 :(得分:40)

虽然问题已经多次回答, 这个问题的简单解决方案尚未列出。

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

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

答案 13 :(得分:38)

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

new = dict_merge(old, extras)

在这些阴暗和可疑的答案中,这个光辉的例子是在Python中合并词汇的唯一好方法,由独裁者终身认可 Guido van Rossum 自己!其他人提出了其中的一半,但没有把它放在一个函数中。

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

给出:

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

答案 14 :(得分:32)

如果你认为lambdas是邪恶的,那就不要再读了。 根据要求,您可以使用一个表达式编写快速且内存有效的解决方案:

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}

如上所述,使用两行或编写函数可能是更好的方法。

答案 15 :(得分:26)

是pythonic。使用comprehension

z={i:d[i] for d in [x,y] for i in d}

>>> print z
{'a': 1, 'c': 11, 'b': 10}

答案 16 :(得分:23)

在python3中,items方法no longer returns a list,而不是视图,它就像一个集合。在这种情况下,您需要使用集合联合,因为与+的连接将不起作用:

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

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

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

我更喜欢这种符号,因为将它看作是一个联合操作而不是连接似乎更自然(如标题所示)。

修改

python 3还有几点。首先,请注意dict(x, **y)技巧在python 3中不起作用,除非y中的键是字符串。

此外,Raymond Hettinger的Chainmap answer非常优雅,因为它可以将任意数量的dicts作为参数,但from the docs看起来它依次查看每个dicts的列表查找:

  

查找会连续搜索基础映射,直到找到密钥。

如果你的应用程序中有很多查找,这会让你失望:

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

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

答案 17 :(得分:18)

使用保留顺序的itertools的简单解决方案(后面的dicts优先)

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}

答案 18 :(得分:18)

滥用导致Matthew's answer的单表达式解决方案:

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

你说你想要一个表达式,所以我滥用lambda来绑定一个名字,并使用元组来覆盖lambda的一个表达式限制。随意畏缩。

如果您不关心复制它,当然也可以这样做:

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

答案 19 :(得分:17)

两个词典

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表现不佳。见https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/

答案 20 :(得分:13)

即使这个字典的答案很好,但这里定义的方法实际上都没有进行深层字典合并。

示例如下:

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

&#39;一个&#39;参赛作品应该有深度_2和#39;和&#39;额外&#39;如果它真的是合并的话,作为其词典中的项目。

也使用链,不起作用:

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

结果:

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

rcwesick给出的深度合并也会产生相同的结果。

是的,它可以合并样本字典,但它们都不是合并的通用机制。一旦我编写了一个执行真正合并的方法,我将在稍后更新。

答案 21 :(得分:12)

New在Python 3.9中:使用联合运算符(|)合并与dict类似的set

>>> d = {'a': 1, 'b': 2}
>>> e = {'a': 9, 'c': 3}
>>> d | e
{'a': 9, 'b': 2, 'c': 3}

对于匹配键,dict优先

这也适用于|=就地修改dict

>>> e |= d    # e = e | d
>>> e
{'a': 1, 'c': 3, 'b': 2}

答案 22 :(得分:10)

借鉴这里和其他地方的想法,我理解了一个功能:

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。

答案 23 :(得分:9)

迄今为止列出的解决方案的问题是,在合并的字典中,键“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}

答案 24 :(得分:8)

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

答案 25 :(得分:8)

这可以通过单个词典理解来完成:

{{1}}

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

答案 26 :(得分:8)

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

这可以解决您的问题。

答案 27 :(得分:7)

(仅适用于Python2.7 *; Python3 *有更简单的解决方案。)

如果您不反对导入标准库模块,则可以执行

from functools import reduce

def merge_dicts(*dicts):
    return reduce(lambda a, d: a.update(d) or a, dicts, {})

or a中的lambda位是必要的,因为成功时dict.update始终返回None。)

答案 28 :(得分:7)

在Python 3.9中

基于PEP 584,Python的新版本引入了两个新的字典运算符:联合(|)和就地联合(| =)。您可以使用|合并两个字典,而| =将在适当的位置更新字典:

>>> pycon = {2016: "Portland", 2018: "Cleveland"}
>>> europython = {2017: "Rimini", 2018: "Edinburgh", 2019: "Basel"}

>>> pycon | europython
{2016: 'Portland', 2018: 'Edinburgh', 2017: 'Rimini', 2019: 'Basel'}

>>> pycon |= europython
>>> pycon
{2016: 'Portland', 2018: 'Edinburgh', 2017: 'Rimini', 2019: 'Basel'}

如果d1和d2是两个字典,则d1 | d2{**d1, **d2}的作用相同。 |运算符用于计算union of sets,因此您可能已经很熟悉这种表示法了。

使用|的一个优点是,它可以处理不同的类似于字典的类型,并通过合并来保持类型:

>>> from collections import defaultdict
>>> europe = defaultdict(lambda: "", {"Norway": "Oslo", "Spain": "Madrid"})
>>> africa = defaultdict(lambda: "", {"Egypt": "Cairo", "Zimbabwe": "Harare"})

>>> europe | africa
defaultdict(<function <lambda> at 0x7f0cb42a6700>,
  {'Norway': 'Oslo', 'Spain': 'Madrid', 'Egypt': 'Cairo', 'Zimbabwe': 'Harare'})

>>> {**europe, **africa}
{'Norway': 'Oslo', 'Spain': 'Madrid', 'Egypt': 'Cairo', 'Zimbabwe': 'Harare'}

当您要有效处理丢失的密钥时,可以使用defaultdict。请注意,|保留defaultdict,而{**europe, **africa}保留defaultdict。

|对于字典的工作方式与+对于列表的工作方式之间有一些相似之处。实际上,+运算符也是originally proposed,用于合并字典。当您查看就地运算符时,这种对应关系变得更加明显。

|=的基本用法是在适当的位置更新字典,类似于.update()

>>> libraries = {
...     "collections": "Container datatypes",
...     "math": "Mathematical functions",
... }
>>> libraries |= {"zoneinfo": "IANA time zone support"}
>>> libraries
{'collections': 'Container datatypes', 'math': 'Mathematical functions',
 'zoneinfo': 'IANA time zone support'}

当您将字典与|合并时,两个字典都必须具有正确的字典类型。另一方面,就地运算符(|=)很乐意使用任何类似于字典的数据结构:

>>> libraries |= [("graphlib", "Functionality for graph-like structures")]
>>> libraries
{'collections': 'Container datatypes', 'math': 'Mathematical functions',
 'zoneinfo': 'IANA time zone support',
 'graphlib': 'Functionality for graph-like structures'}

答案 29 :(得分:6)

.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

答案 30 :(得分:5)

仅适用于Python 3.9 +

合并(|)和更新(| =)运算符已添加到内置dict类中。

>>> d = {'spam': 1, 'eggs': 2, 'cheese': 3}
>>> e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}
>>> d | e
{'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}

扩充作业版本就地运行:

>>> d |= e
>>> d
{'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}

请参见PEP 584

答案 31 :(得分:4)

我知道这不符合问题的具体细节(&#34;一个班轮&#34;),但由于没有上面的答案进入这个方向,而很多很多答案解决了表现问题,我觉得我应该贡献自己的想法。

根据用例的不同,可能没有必要创建一个真实的&#34;合并的给定输入词典的字典。在许多情况下,执行此操作的视图就足够了,i。即一个对象就像合并的字典一样,不会完全计算它。可以这么说,合并字典的懒惰版本。

在Python中,这很简单,可以使用我帖子末尾显示的代码完成。这个问题,原始问题的答案是:

z = MergeDict(x, y)

当使用这个新对象时,它将表现得像一个合并的字典,但它将具有恒定的创建时间和恒定的内存占用,同时保持原始字典不受影响。创建它比提出的其他解决方案更便宜。

当然,如果您经常使用结果,那么您将在某个时刻达到限制,创建真正的合并字典将是更快的解决方案。正如我所说,这取决于你的用例。

如果您觉得自己希望真正合并dict,那么调用dict(z)会产生它(但当然比其他解决方案更昂贵,所以这值得一提)

您也可以使用此类创建一种写时复制字典:

a = { 'x': 3, 'y': 4 }
b = MergeDict(a)  # we merge just one dict
b['x'] = 5
print b  # will print {'x': 5, 'y': 4}
print a  # will print {'y': 4, 'x': 3}

这是MergeDict的直接代码:

class MergeDict(object):
  def __init__(self, *originals):
    self.originals = ({},) + originals[::-1]  # reversed

  def __getitem__(self, key):
    for original in self.originals:
      try:
        return original[key]
      except KeyError:
        pass
    raise KeyError(key)

  def __setitem__(self, key, value):
    self.originals[0][key] = value

  def __iter__(self):
    return iter(self.keys())

  def __repr__(self):
    return '%s(%s)' % (
      self.__class__.__name__,
      ', '.join(repr(original)
          for original in reversed(self.originals)))

  def __str__(self):
    return '{%s}' % ', '.join(
        '%r: %r' % i for i in self.iteritems())

  def iteritems(self):
    found = set()
    for original in self.originals:
      for k, v in original.iteritems():
        if k not in found:
          yield k, v
          found.add(k)

  def items(self):
    return list(self.iteritems())

  def keys(self):
    return list(k for k, _ in self.iteritems())

  def values(self):
    return list(v for _, v in self.iteritems())

答案 32 :(得分:4)

您可以使用toolz.merge([x, y])

答案 33 :(得分:4)

如果你不介意改变x

x.update(y) or x

简单,易读,高效。您知道 update()始终返回None,这是一个错误值。所以它总是会评估为x

标准库中的变异方法,如update,按惯例返回None,所以这个技巧也适用于那些。

如果您正在使用不遵循此约定的库,则可以使用元组显示和索引将其设置为单个表达式,而不是or,但它是&#39;不可读。

(x.update(y), x)[-1]

如果您尚未在变量中使用x,则可以使用lambda制作本地而不使用赋值语句。这相当于使用lambda作为 let表达式,这是函数式语言中的常用技术,而非untythonic。

(lambda x: x.update(y) or x)({'a':1, 'b': 2})

如果您确实需要副本,PEP 448最好是{**x, **y}。但如果没有,也可以在这里工作。

(lambda z: z.update(y) or z)(x.copy())

答案 34 :(得分: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}

请注意理解中if else的语法

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

答案 35 :(得分:4)

我用perfplot对建议进行了基准测试,发现旧的很好

temp = x.copy()
temp.update(y)

与新版本一起是最快的解决方案

x | y

enter image description here


用于重现情节的代码:

from collections import ChainMap
from itertools import chain
import perfplot


def setup(n):
    x = dict(zip(range(n), range(n)))
    y = dict(zip(range(n, 2 * n), range(n, 2 * n)))
    return x, y


def copy_update(data):
    x, y = data
    temp = x.copy()
    temp.update(y)
    return temp


def add_items(data):
    x, y = data
    return dict(list(x.items()) + list(y.items()))


def curly_star(data):
    x, y = data
    return {**x, **y}


def chain_map(data):
    x, y = data
    return dict(ChainMap({}, y, x))


def itertools_chain(data):
    x, y = data
    return dict(chain(x.items(), y.items()))


def python39_concat(data):
    x, y = data
    return x | y


perfplot.show(
    setup=setup,
    kernels=[
        copy_update,
        add_items,
        curly_star,
        chain_map,
        itertools_chain,
        python39_concat,
    ],
    labels=[
        "copy_update",
        "dict(list(x.items()) + list(y.items()))",
        "{**x, **y}",
        "chain_map",
        "itertools.chain",
        "x | y",
    ],
    n_range=[2 ** k for k in range(15)],
    xlabel="len(x), len(y)",
    equality_check=None,
)

答案 36 :(得分:3)

OP的两个词典的结合将是:

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

具体而言,两个实体(xy)的并集包含x和/或y的所有元素。 不幸的是,OP要求的不是工会,尽管该职位的名称。

我的下面的代码既不优雅也不是单行,但我相信它与联合的含义一致。

来自OP的例子:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}

z = {}
for k, v in x.items():
    if not k in z:
        z[k] = [(v)]
    else:
        z[k].append((v))
for k, v in y.items():
    if not k in z:
        z[k] = [(v)]
    else:
        z[k].append((v))

{'a': [1], 'b': [2, 10], 'c': [11]}

是否需要列表可以更改,但如果字典包含列表(和嵌套列表)作为任一字典中的值,则上述操作将起作用。

答案 37 :(得分:3)

感谢scheduled for 20 October, 2019,当Python 3.8发行(PEP 572: Assignment Expressions)时会有一个新选项。新的赋值表达式运算符:=允许您分配copy的结果,并仍然使用它来调用update,从而使合并的代码只有一个表达式,而不是两个语句,从而改变了:

newdict = dict1.copy()
newdict.update(dict2)

收件人:

(newdict := dict1.copy()).update(dict2)

同时在各个方面都表现相同。如果还必须返回结果dict(您要求返回dict的表达式;则上面的代码会创建并分配给newdict,但不会返回它,因此您无法使用它将参数直接传递给函数la myfunc((newdict := dict1.copy()).update(dict2)),然后将or newdict添加到末尾(因为update返回None,这很虚假,然后它将求值并返回newdict作为表达式的结果):

(newdict := dict1.copy()).update(dict2) or newdict

重要警告:通常,我不建议使用此方法,而赞成:

newdict = {**dict1, **dict2}

解包的方法更清晰(对于任何一开始就知道广义解包的人,which you should),根本不需要名称(因此,构造一个临时的立即传递给函数或包含在list / tuple文字等中),并且几乎肯定也更快,(在CPython上)大致等同于:

newdict = {}
newdict.update(dict1)
newdict.update(dict2)

,但使用具体的dict API在C层完成,因此不涉及动态方法查找/绑定或函数调用分派开销(其中(newdict := dict1.copy()).update(dict2)不可避免地与原始的两层相同在行为上,通过动态查找/绑定/方法调用,分步执行工作。

它也更具扩展性,因为合并三个dict很明显:

 newdict = {**dict1, **dict2, **dict3}

在使用赋值表达式的地方不会像这样缩放;您可以获得的最接近的是:

 (newdict := dict1.copy()).update(dict2), newdict.update(dict3)

或没有None的临时元组,但是对每个None结果进行了真实性测试:

 (newdict := dict1.copy()).update(dict2) or newdict.update(dict3)

这两种方法显然都很丑陋,并且效率进一步降低(要么浪费tuple的临时None来进行逗号分隔,要么对每个update的{ {1}}返回None分隔。)

赋值表达式方法的唯一真正优势在于:

  1. 您有需要处理orset的通用代码(它们都支持dictcopy,因此代码大致可以按您期望的那样工作)
  2. 您希望接收任意类似dict的对象,而不仅仅是update本身,并且必须保留左侧的类型和语义(而是而不是以简单的dict结尾)。尽管dict可能会起作用,但会涉及一个额外的临时myspecialdict({**speciala, **specialb}),并且如果dict具有普通myspecialdict无法保留的功能(例如现在的常规dict根据键的第一次出现保留顺序,并根据键的最后出现保留值;您可能希望根据键的 last 保留顺序来保留顺序,以便更新值到最后),那么语义将是错误的。由于赋值表达式版本使用命名方法(可能会重载以使其正常运行),因此它根本不会创建dict(除非dict已经是dict1),并且保留了原始方法。类型(和原始类型的语义),同时避免任何临时使用。

答案 38 :(得分:1)

从 Python 3.9+ 开始,有一种更简单的方法来合并两个字典

>>> x = {'a': 1, 'b': 2}
>>> y = {'b': 10, 'c': 11}
>>> merged = {**x, **y}

答案 39 :(得分:1)

一个 hacky one-liner for 2.5+ :

>>> a = dict(x=2, y=3)
>>> b = dict(y=4, z=5)
>>> c = 'No Effect' if a.update(b) else a
>>> c
{'x': 2, 'y': 4, 'z': 5}

注意事项:

  • dict.update 就地修改 dict,因此计算结果为 None
  • 在表达式 A if C else B 中,首先计算 C。见here

所以在这里,a.update(b) 首先被评估,a 被更新为 b 并且操作结果在 None,因此表达式将始终返回 { 中给定的值{1}} 条件,即 else。由于 a 已被修改,因此它将返回 a 的新值,即更新后的 dict。

改进

这可以进一步改进,它可以用于更旧的版本(也可能是 python 1.0?):

a

这里也是,第一部分产生>>> c = a.update(b) or a ,因此它总是返回第二部分,但由于更新操作已经完成,它总是返回更新后的字典。

批评

  • 两种解决方案都修改了 None 的值,因此如果想要保持两个输入字典不变,这不是一个好主意。< /li>

改进

如果需要 a 的副本,可以稍微修改第二个:

a

注意事项

  • 它(尤其是第一个)变得丑陋且对于大于 2 的任意数量的 dict 来说都是不切实际的
  • 此外,这是不明确,这是非pythonic

尽管这些解决方案非常快,尤其是 >>> a = dict(x=2, y=3) >>> b = dict(y=4, z=5) >>> a, c = a.copy(), a.update(b) or a >>> c {'x': 2, 'y': 4, 'z': 5} >>> d = dict(m=10, n=11) >>> a, c = a.copy(), a.update(b) or a.update(d) or a >>> c {'x': 2, 'y': 4, 'z': 5, 'm': 10, 'n': 11} >>> a {'x': 2, 'y': 4} 方法,它可能比新的 python 3.9 联合运算符更快(不完全确定,进一步需要测试,如果有人想在之后添加它,欢迎他们),由于上述原因,我不推荐这些方法。 为了完整起见,添加了它。

答案 40 :(得分:1)

我有一个未在此处指定的解决方案

z = {}
z.update(x) or z.update(y)

这不会更新x和y。性能?我不认为它会非常缓慢: - )

注意:它应该是'或'操作而不是'和'操作。编辑纠正代码。

答案 41 :(得分:1)

这是Python 3.5或更高版本的表达式,它使用reduce合并字典:

>>> from functools import reduce
>>> l = [{'a': 1}, {'b': 2}, {'a': 100, 'c': 3}]
>>> reduce(lambda x, y: {**x, **y}, l, {})
{'a': 100, 'b': 2, 'c': 3}

注意:即使字典列表为空或只包含一个元素,这也可以。

答案 42 :(得分:1)

如果我能用一行字符串化方法击败接受的答案,我很好奇:

我尝试了5种方法,前面没有提到过 - 所有这些方法都是正确的答案 - 我无法接近。

所以......为了省去麻烦,也许还能满足好奇心:

import json
import yaml
import time
from ast import literal_eval as literal

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

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}

start = time.time()
for i in range(10000):
    z = yaml.load((str(x)+str(y)).replace('}{',', '))
elapsed = (time.time()-start)
print (elapsed, z, 'stringify yaml')

start = time.time()
for i in range(10000):
    z = literal((str(x)+str(y)).replace('}{',', '))
elapsed = (time.time()-start)
print (elapsed, z, 'stringify literal')

start = time.time()
for i in range(10000):
    z = eval((str(x)+str(y)).replace('}{',', '))
elapsed = (time.time()-start)
print (elapsed, z, 'stringify eval')

start = time.time()
for i in range(10000):
    z = {k:int(v) for k,v in (dict(zip(
            ((str(x)+str(y))
            .replace('}',' ')
            .replace('{',' ')
            .replace(':',' ')
            .replace(',',' ')
            .replace("'",'')
            .strip()
            .split('  '))[::2], 
            ((str(x)+str(y))
            .replace('}',' ')
            .replace('{',' ').replace(':',' ')
            .replace(',',' ')
            .replace("'",'')
            .strip()
            .split('  '))[1::2]
             ))).items()}
elapsed = (time.time()-start)
print (elapsed, z, 'stringify replace')

start = time.time()
for i in range(10000):
    z = json.loads(str((str(x)+str(y)).replace('}{',', ').replace("'",'"')))
elapsed = (time.time()-start)
print (elapsed, z, 'stringify json')

start = time.time()
for i in range(10000):
    z = merge_two_dicts(x, y)
elapsed = (time.time()-start)
print (elapsed, z, 'accepted')

结果:

7.693928956985474 {'c': 11, 'b': 10, 'a': 1} stringify yaml
0.29134678840637207 {'c': 11, 'b': 10, 'a': 1} stringify literal
0.2208399772644043 {'c': 11, 'b': 10, 'a': 1} stringify eval
0.1106564998626709 {'c': 11, 'b': 10, 'a': 1} stringify replace
0.07989692687988281 {'c': 11, 'b': 10, 'a': 1} stringify json
0.005082368850708008 {'c': 11, 'b': 10, 'a': 1} accepted

我从中学到的是json方法是从字典字符串返回字典的最快方式(尝试的方法);我认为使用ast的常规方法要快得多(大约1/4的时间)。我还了解到,应该不惜一切代价避免使用yaml方法。

是的,我知道这不是最好/最正确的方式,所以请不要贬低负面遗忘,零就好了。我很好奇它是否更快,它不是;我贴出来证明这一点。

答案 43 :(得分:1)

这个问题被标记为python-3x,但考虑到这是一个相对较新的补充,并且投票最多,被接受的答案广泛涉及Python 2.x解决方案,我敢于添加一个借用的一个班轮Python 2.x列表理解的一个令人恼火的特征,即名称泄露 ......

$ python2
Python 2.7.13 (default, Jan 19 2017, 14:48:08) 
[GCC 6.3.0 20170118] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> [z.update(d) for z in [{}] for d in (x, y)]
[None, None]
>>> z
{'a': 1, 'c': 11, 'b': 10}
>>> ...

我很高兴地说上述内容在任何版本的Python 3上都不再适用。

答案 44 :(得分:0)

一些无需使用任何Python模块(无依赖项)且代码很少的代码即可解决此问题的方法。

所有Python版本(使用Lambda):

merge_dicts = lambda old, new: old.update(new) or old
  

Python版本> = 3.5:

def merge_dicts(old, new):
    return {**old, **new} 
  

旧Python版本:

def merge_dicts(old, new):
    merged = old.copy()
    merged.update(new)
    return merged

此示例将合并新旧值,同时擦除旧值。

  

用法:

old = {'name': 'Kevin', 'phone_number': '+33 12 34 45 67'}
new = {'name': 'Kevin', 'phone_number': '+33 88 88 88 88'}

print(merge_dicts(old, new))
  

输出:

{'name': 'Kevin', 'phone_number': '+33 88 88 88 88'}

如果您必须处理从旧版本合并到新版本的倍数,而又不丢失任何数据,则下面的示例方法使用一系列字典:

  

所有Python版本:

def merge_dicts(old, news):
    merged = old.copy()
    for new in news:
        merged.update(new)
    return merged
  

用法:

old = {'name': 'Kevin', 'phone_number': '+33 12 34 45 67'}
new_01 = {'name': 'Kevin', 'phone_number': '+33 77 77 77 77', 'age': 28}
new_02 = {'name': 'SabK', 'phone_number': '+33 88 88 88 89'}
new_03 = {'phone_number': '+33 99 99 99 99'}

print(merge_dicts(old, [new_01, new_02, new_03]))
  

输出:

{'phone_number': '+33 99 99 99 99', 'age': 28, 'name': 'SabK'}

在此示例中,新字典将从旧字典(第一个参数)生成,然后从数组的第一个元素到最后一个依次更新(new_01> new_02> new_03)

最后,您将从所有字典中获取所有数据,并将更新已更改的值。当您处理经常变化的数据时,此功能非常有用。

答案 45 :(得分:0)

您可以使用函数来做到这一点:

def append(d1, d2):
    d1.update(d2)
    return d1

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = append(x, y)
print(z) #{'a': 1, 'b': 10, 'c': 11}

答案 46 :(得分:0)

对于Python 3:

from collections import ChainMap
a = {"a": 1, "b":2}
b = {"c":5, "d":8}
dict(ChainMap(a,b))  # {"a":1, "b":2, "c":5, "d":8}

如果两个字典中的键相同,则ChanMap将使用第一个键的值,而忽略第二个键的值。 干杯!

答案 47 :(得分:0)

相反,例如,如果您想通过添加值来组合两个字典,我们可以依靠Collections模块(我不确定这是否存在于12年前-首次提出问题时):

from collections import Counter
x = Counter({'a': 1, 'b': 2})
y = Counter({'b': 10, 'c': 11})

然后x + y等于

Counter({'a': 1, 'b': 12, 'c': 11})

答案 48 :(得分:-1)

As of Python 3.9PEP584,有一种新方法可用于此:

z = x.union(y)

现在可以按需工作,而无需修改x或y。

y值将使用相同的键覆盖x值。

您现在也可以使用union merge syntax

z = x | y

给出相同的结果。