HOWTO · Python

如何在 Python 2 和 3 中合并两个字典

本教程介绍了如何在 Python 2 和 3 中合并两个字典。

本页内容

假设我们有两个字典 A 和 B 需要进行合并,其中 B 的值将取代 A 的值,如果它们有相同的键 key 的话。

A = {"x": 10, "y": 20}
B = {"y": 30, "z": 40}

Python dictionary 对象有一个原生方法 update() 来用 B 来更新字典 A,

A.update(B)

但是 A 的数据将被替换,而不是返回包含合并 A 和 B 的新字典。

我们将介绍如何合并两个字典并返回新字典的方法。

Python 2.7 字典合并

字典推导式方法-1

C = {key: value for d in (A, B) for key, value in d.items()}

d.itmes() 以字典 d 的 2 元组的形式返回 (key, value) 对的列表。

此方法使用嵌套字典推导式合并两个字典。for 的正确顺序应格外注意。它应该是,

flattern_patterns = [planet for sublist in planets for planet in sublist]

字典推导式方法-2

我们还可以使用 dict() 方法来初始化新字典。

C = dict((key, value) for d in (A, B) for key, value in d.items())

从技术上讲,它与上述方法几乎相同,但是在性能上有所不同,我们将在后面提到。

itertools.chain 方法

itertools 模块标准化了一组核心 iterator 构建块。它具有快速和高效存储等功能。

itertools.chain 返回一个链对象,该对象的 .next() 方法从第一个可迭代对象返回元素,直到用尽为止,然后从下一个可迭代对象返回元素,直到所有元素用尽。

dict(itertools.chain(A.iteritems(), B.iteritems()))

iteritems() 返回字典 (key, value) 元素的迭代器。

因此,以上脚本将返回包含 A 和 B 元素的字典。

copy 和 update 方法

如开头所述,update 可以合并 A 和 B,但是将就地替换字典。我们可以使用 copy 方法复制字典 A。

m = A.copy()
C = m.update(B)

合并方法性能分析和比较

import timeit

A = {"x": 10, "y": 20}
B = {"y": 30, "z": 40}

SETUP_CODE = """
A = {'x': 10, 'y': 20}
B = {'y': 30, 'z': 40}
"""

TEST_CODE = """
{key: value for d in (A, B) for key, value in d.items()}
"""
print min(timeit.repeat(setup=SETUP_CODE, stmt=TEST_CODE, repeat=3, number=10000))

TEST_CODE = """
dict((key, value) for d in (A, B) for key, value in d.items())
"""
print min(timeit.repeat(setup=SETUP_CODE, stmt=TEST_CODE, repeat=3, number=10000))

TEST_CODE = """
dict(itertools.chain(A.iteritems(), B.iteritems()))
"""
print min(timeit.repeat(setup=SETUP_CODE, stmt=TEST_CODE, repeat=3, number=10000))

SETUP_CODE = """
def merge_dicts(a, b):
    m = a.copy()
    m.update(b)
    return m

A = {'x': 10, 'y': 20}
B = {'y': 30, 'z': 40}
"""

TEST_CODE = """
merge_dicts(A, B)
"""
print min(timeit.repeat(setup=SETUP_CODE, stmt=TEST_CODE, repeat=3, number=10000))

结果是

0.0162378
0.029774
0.019975
0.0110059
方法 性能 排名
{key: value for d in (A, B) for key, value in d.items()} 0.0162378 2
dict((key, value) for d in (A, B) for key, value in d.items()) 0.029774 4
dict(itertools.chain(A.iteritems(), B.iteritems())) 0.019975 3
merge_dicts(a, b) 0.0110059 1

Python 3.5(及更高版本)字典合并方法

从 Python 3.5 开始,除了与 Python 2.7 中相同的方法外,它还具有 PEP-448 中 引入的 ** unpacking 运算符。它可以解压缩任意数量的 dictionary 对象。

注意
d.iteritems() 在 Python 3 中已弃用。请参阅 PEP-469
>>> C = {**A, **B}
>>> C
{'x': 10, 'y': 30, 'z': 40}
import timeit

A = {"x": 10, "y": 20}
B = {"y": 30, "z": 40}

SETUP_CODE = """
A = {'x': 10, 'y': 20}
B = {'y': 30, 'z': 40}
"""

TEST_CODE = """
{**A, **B}
"""
print(min(timeit.repeat(setup=SETUP_CODE, stmt=TEST_CODE, repeat=3, number=10000)))

TEST_CODE = """
{key: value for d in (A, B) for key, value in d.items()}
"""
print(min(timeit.repeat(setup=SETUP_CODE, stmt=TEST_CODE, repeat=3, number=10000)))

TEST_CODE = """
dict((key, value) for d in (A, B) for key, value in d.items())
"""
print(min(timeit.repeat(setup=SETUP_CODE, stmt=TEST_CODE, repeat=3, number=10000)))

TEST_CODE = """
dict(itertools.chain(A.items(), B.items()))
"""
print(min(timeit.repeat(setup=SETUP_CODE, stmt=TEST_CODE, repeat=3, number=10000)))

SETUP_CODE = """
def merge_dicts(a, b):
    m = a.copy()
    m.update(b)
    return m

A = {'x': 10, 'y': 20}
B = {'y': 30, 'z': 40}
"""

TEST_CODE = """
merge_dicts(A, B)
"""
print(min(timeit.repeat(setup=SETUP_CODE, stmt=TEST_CODE, repeat=3, number=10000)))
0.0017047999999999508
0.009127499999999955
0.0168952
0.01078009999999996
0.005767999999999995
方法 性能 排名
{**A, **B} 0.0017047999999999508 1
{key: value for d in (A, B) for key, value in d.items()} 0.009127499999999955 3
dict((key, value) for d in (A, B) for key, value in d.items()) 0.0168952 5
dict(itertools.chain(A.items(), B.items())) 0.01078009999999996 4
merge_dicts(a, b) 0.005767999999999995 2

合并方法结论

在 Python 2.7,copy 和 update 是最好的方法。

m = A.copy()
C = m.update(B)

在 Python 3.5+ 中,字典解压缩方法是最好的。

{**A, **B}