最省事的是用 deepmerge 库,它专为嵌套字典合并设计,默认右覆盖左、同为字典时递归合并;而 update() 和 | 只浅层合并,ChainMap 仅逻辑链式查找不真正融合,手写需注意字符串/tuple/None 等边界。

用 deepmerge 库最省事,但得先装好
直接 pip install deepmerge 就行,它专为嵌套字典合并设计,比手写递归更可靠。默认行为是“右覆盖左”,即右边字典的值会覆盖左边同路径的值;如果两边都是字典,则递归合并,不是简单替换。
常见错误是以为 update() 或 |(Python 3.9+ 合并操作符)能处理嵌套——它们只做浅层合并,遇到内层字典就直接替换了,不会往下钻。
pip install deepmerge- 导入后用
Merger类可自定义策略,比如遇到列表时是拼接还是去重 - 基础用法:
from deepmerge import always_merger; result = always_merger.merge(dict1, dict2)
自己写递归合并函数要注意键类型和容器判断
手写时最容易漏掉的是:不是所有“可迭代”对象都要递归,比如字符串、bytes、tuple 虽然可迭代,但不该当字典处理;只有 dict 才该继续下钻。
另一个坑是没处理 None 值——如果某一层左边是 None,右边是字典,直接递归会报错。
立即学习“Python免费学习笔记(深入)”;
- 用
isinstance(obj, dict)判断,别用hasattr(obj, 'keys'),后者对 Mapping 子类也不够稳 - 合并前先检查两边是否都为
dict,否则按“右覆盖左”策略直接赋值 - 示例片段:
if isinstance(v1, dict) and isinstance(v2, dict): return {k: deep_merge(v1.get(k), v2.get(k)) for k in set(v1) | set(v2)}
用 collections.ChainMap 是假合并,别误当真
ChainMap 只是逻辑上链式查找,并不生成新字典,也不递归合并嵌套结构。它适合只读场景下的配置叠加,比如环境变量 + 默认配置,但不能用于需要真正融合数据的业务逻辑。
典型误用:以为 ChainMap(dict1, dict2) 能让 dict1['a']['b'] 和 dict2['a']['c'] 自动合成一个 a 字典——它做不到。
-
ChainMap查找顺序是从左到右,找到第一个匹配键就返回,不会合并值 - 要转成真实字典得调用
dict(),但这时嵌套部分仍是原样,没发生深度合并 - 适合场景:临时组合多层配置,且明确知道各层 key 不重叠
性能敏感时别无脑递归,考虑用 jsonpatch 或路径扁平化
当字典层级深、数量大(比如上万条配置项),纯递归容易栈溢出或变慢。这时候可以先把嵌套结构压平成 {"a.b.c": 123} 形式,用普通 dict 合并,再还原。
或者用 jsonpatch 库把第二个字典转成 patch 操作序列,应用到第一个字典上——它内部做了路径解析和类型检查,比手动递归更健壮。
- 扁平化工具可用
flatten_dict第三方包,或自己写带分隔符的遍历 -
jsonpatch.make_patch(old, new)返回 patch 对象,patch.apply(old)得到合并结果 - 注意:
jsonpatch要求输入是 JSON-serializable 类型,不支持自定义对象或函数
deepmerge 就够了,但一旦涉及大量数据或特殊类型,就得提前想清楚边界。


















