将一个字典附加到另一个字典

555

我有两个现有的字典,我希望将它们中的一个“附加”到另一个上面。这意味着其他字典的键和值应该被添加到第一个字典中。例如:

orig = {
   'A': 1,
   'B': 2,
   'C': 3,
}

extra = {
   'D': 4,
   'E': 5,
}

dest = # Something here involving orig and extra

print dest
{
   'A': 1,
   'B': 2,
   'C': 3,
   'D': 4,
   'E': 5
}

我认为这一切都可以通过一个 for 循环来实现(也许?),但是否存在某些字典方法或其他模块可以替我完成这项工作?我使用的实际字典非常大...


29
一些答案指出orig.update(extra)可以完成这项工作。但请注意,如果extraorig具有重叠的键,则最终值将来自于extra。例如,d1={1: 1, 2: 2}; d2={2: 'ha!', 3: 3}; d1.update(d2)将导致d1包含{1: 1, 2: 'ha!', 3: 3} - Steven Rumbalski
7个回答

779
你可以这样做。
orig.update(extra)

或者,如果您不想修改 orig ,请先创建一个副本:

dest = dict(orig)  # or orig.copy()
dest.update(extra)
请注意,如果extra和orig具有重叠的键,则最终值将来自于extra。例如,
>>> d1 = {1: 1, 2: 2}
>>> d2 = {2: 'ha!', 3: 3}
>>> d1.update(d2)
>>> d1
{1: 1, 2: 'ha!', 3: 3}

4
有一个叫做 dict.copy() 的函数,它和你的复制方法一样创建浅拷贝。 - sleeplessnerd
1
我以前见过 dict(**orig) 这个用法。相比于 dict(orig),它有什么优势呢? - DSM
6
使用dict(**orig)会创建一个新的临时字典,用作字典构造函数的关键字参数。构造函数会将此参数中的值复制到自身中。因此,使用dict(**orig)会创建一个额外的字典。当原始问题中的字典很大时,这是一种浪费。 - Martin Geisler
1
虽然如此,我刚刚在标准的CPython(2.7)上使用timeit进行了快速实证测试,结果dict(**orig)稍微更快。你的情况可能有所不同,这取决于你的实现方式 - 但是我并不完全确定在所有实现中,在这种情况下使用**习惯用语确实会产生额外的开销,也许是因为dict是一种内置类型。 - HardlyKnowEm
16
如果您的键不是有效的关键字参数,这将会出错。例如:x = {1: 1}; dict(**x) - Rob Wouters
显示剩余3条评论

183

将一个字典添加到另一个字典有两种方法:

更新(就地修改orig

orig.update(extra)    # Python 2.7+
orig |= extra         # Python 3.9+

Merge(创建一个新字典)

# Python 2.7+
dest = collections.ChainMap(orig, extra)
dest = {k: v for d in (orig, extra) for (k, v) in d.items()}

# Python 3
dest = {**orig, **extra}          
dest = {**orig, 'D': 4, 'E': 5}

# Python 3.9+ 
dest = orig | extra

注意事项

请注意,这些操作是非交换的。在所有情况下,后者胜出。例如:

orig  = {'A': 1, 'B': 2}
extra = {'A': 3, 'C': 3}

dest = orig | extra
# dest = {'A': 3, 'B': 2, 'C': 3}

dest = extra | orig
# dest = {'A': 1, 'B': 2, 'C': 3}
值得注意的是,只有从Python 3.7 (和CPython 3.6) 开始,dict才是有序的。因此,在之前的版本中,字典中项目的顺序可能会有所不同。

1
为什么会这样? - gosuto
很适合进行一级字典合并! - Zhong Ri

33

dict.update() 看起来可以满足你的需求...

>> orig.update(extra)
>>> orig
{'A': 1, 'C': 3, 'B': 2, 'E': 5, 'D': 4}
>>> 

也许您不想更新原始字典,而是要在副本上操作:

>>> dest = orig.copy()
>>> dest.update(extra)
>>> orig
{'A': 1, 'C': 3, 'B': 2}
>>> dest
{'A': 1, 'C': 3, 'B': 2, 'E': 5, 'D': 4}

29

假设您不想改变orig,您可以像其他答案一样进行复制和更新,或者您可以通过将两个字典中的所有项传递到dict构造函数中一次性创建一个新字典:

from itertools import chain
dest = dict(chain(orig.items(), extra.items()))

或者不使用itertools:

dest = dict(list(orig.items()) + list(extra.items()))
注意,只有在Python 3中需要将items()的结果传递给list()。在Python 2.x中,dict.items()已经返回了一个列表,因此您可以直接执行dict(orig.items() + extra.items())
作为更一般的用例,假设您有一个较大的字典列表,您想将它们合并成一个单独的字典,您可以执行以下操作:
from itertools import chain
dest = dict(chain.from_iterable(map(dict.items, list_of_dicts)))

2
实际上,我更喜欢这个,因为你可以在同一个表达式中“更新”字典,并将其用作参数,例如:SomeClass(**dict(args.items()+{'special':a_value,}.items())) - carlosayam

20

将两个字典合并的三行代码:

dest = {}
dest.update(orig)
dest.update(extra)

这将创建一个名为dest的新字典,而不会修改origextra

注意:如果一个键在origextra中具有不同的值,则extra将覆盖orig


3
可在 Python 2 和 Python 3 中使用。 - jkdev

9
这��有一个方法叫做.update() :) update([other]) 方法可以用来向字典中添加其他键/值对,覆盖已有的键。返回值为 None。 update() 方法接受另一个字典对象或者一组键/值对(如元组或其他长度为二的可迭代对象)。如果指定了关键字参数,则使用这些键/值对更新字典:d.update(red=1, blue=2)。
从版本 2.4 开始更改:允许参数为键/值对的可迭代对象,并允许关键字参数。

8
我想给出的答案是"use collections.ChainMap",但我刚刚发现这只在Python 3.3中添加了:https://docs.python.org/3.3/library/collections.html#chainmap-objects 您可以尝试从3.3源代码中抄写该类:http://hg.python.org/cpython/file/3.3/Lib/collections/init.py#l763 这里有一个功能较少且与Python 2.x兼容的版本(同一作者):http://code.activestate.com/recipes/305268-chained-map-lookups/ 不需要使用dict.merge扩展或覆盖一个字典,也不需要创建合并两者的额外副本,而是创建一个查找链,按顺序搜索两个字典。由于它不会复制映射,因此ChainMap使用非常少的内存,并查看任何子映射的最新修改。因为顺序很重要,所以您还可以使用链来分层默认值(即用户首选项>配置>环境)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接