在Python开发过程中,经常会遇到需要把多个字典合并成一个的场景,比如处理多来源的配置信息、整合不同模块返回的数据等。不同的合并方式在性能、内存占用、使用效果上都有区别,其中字典解包和ChainMap是两种最常用的方案。

什么是字典解包合并
字典解包是Python 3.5+引入的特性,通过**运算符可以把一个字典的键值对展开,放到新的字典字面量中,从而实现多个字典的合并。它的语法非常简洁,适合快速合并少量字典的场景。
基础用法示例如下:
# 定义三个待合并的字典
dict1 = {"name": "张三", "age": 20}
dict2 = {"gender": "男", "city": "北京"}
dict3 = {"hobby": "编程", "age": 21} # 存在和dict1冲突的键age
# 使用解包合并三个字典
merged_dict = {**dict1, **dict2, **dict3}
print(merged_dict)
# 输出结果:{"name": "张三", "age": 21, "gender": "男", "city": "北京", "hobby": "编程"}
从示例可以看到,当多个字典存在相同键时,后面的字典键值对会覆盖前面的,最终合并后的字典是一个全新的独立字典,和原来的三个字典都没有关联。
什么是ChainMap合并
ChainMap是Python标准库collections模块中的类,它可以将多个字典链接起来,形成一个类似字典的对象,本身不会创建新的字典来存放所有键值对,而是保存对原有字典的引用。
基础用法示例如下:
from collections import ChainMap
# 定义三个待合并的字典
dict1 = {"name": "张三", "age": 20}
dict2 = {"gender": "男", "city": "北京"}
dict3 = {"hobby": "编程", "age": 21}
# 使用ChainMap合并三个字典
chain_map = ChainMap(dict3, dict2, dict1) # 注意顺序,前面的字典优先级更高
print(dict(chain_map))
# 输出结果:{"name": "张三", "age": 21, "gender": "男", "city": "北京", "hobby": "编程"}
ChainMap查询键的时候会按照传入字典的顺序依次查找,找到第一个匹配的键就返回,所以同样存在键冲突时,排在前面的字典的键值对会生效。它支持大部分字典的常用操作,比如获取键、遍历键值对等。
两种方式的核心差异对比
我们可以从多个维度对比两种合并方式的区别,具体如下表:
| 对比维度 | 字典解包 | ChainMap |
|---|---|---|
| 内存占用 | 会创建全新的字典,存储所有键值对,内存占用和合并后的总键值对数量正相关 | 仅保存原有字典的引用,不会复制键值对,内存占用极低 |
| 修改影响 | 合并后的新字典修改不会影响原有字典,原有字典修改也不会影响新字典 | 修改ChainMap的键值对会直接反映到它引用的第一个字典上,原有字典修改也会影响ChainMap的查询结果 |
| 键冲突处理 | 后面的字典覆盖前面的字典的同键内容 | 查找时优先返回第一个出现该键的字典的值,前面的字典优先级更高 |
| 适用场景 | 需要独立的新字典、后续会频繁修改合并结果、字典数量少的场景 | 仅需要临时查看合并后的键值对、不需要修改合并结果、字典数量多或单个字典体积大的场景 |
场景选择建议
根据两种方式的特性,我们可以按照以下原则选择:
- 如果需要得到一个完全独立的合并字典,后续可能会对合并结果做修改,或者需要把合并结果传递给其他函数使用,优先选择字典解包的方式,代码简洁且结果可控。
- 如果只是临时需要查询多个字典合并后的键值对,不需要修改结果,或者原有字典体积很大、数量很多,不想额外占用内存,优先选择ChainMap的方式,性能更好且更省内存。
- 如果需要在合并后的对象上做新增、修改操作,同时希望这些操作不影响原有字典,那么字典解包是更合适的选择,因为ChainMap的修改会直接作用于引用的第一个字典。
注意事项
使用字典解包时需要注意,Python 3.5以下版本不支持该语法,如果是旧版本环境,可以使用dict.update()方法实现合并,不过代码会稍显繁琐。使用ChainMap时,要注意它的键查找顺序和字典的不可变性,如果原有字典被删除,ChainMap可能会出现查询异常。另外ChainMap虽然支持大部分字典操作,但不是所有字典方法都支持,比如popitem()方法在Python 3.7+的ChainMap中是支持的,但低版本可能存在差异,使用时需要确认环境版本。
总的来说,两种方式没有绝对的好坏,结合自己的实际场景选择就能写出更优雅的Python代码。