python 3.9+ 推荐用 | 合并字典,返回新字典、右键覆盖左键、仅一层合并;旧版本可用 解包或 update(),但行为差异大: 解包要求 key 可哈希且顺序敏感,update() 就地修改并返回 none;深度合并需手动实现或借助第三方库。

Python 3.9+ 直接用 | 运算符,老版本用 ** 展开或 update(),但行为差异大,一不小心就覆盖或浅拷贝出错。
用 | 合并字典(Python 3.9+)
这是最直观、不可变的方式:返回新字典,不修改原字典,右操作数的键值会覆盖左操作数同名键。
常见错误是误以为它递归合并嵌套字典——其实只做一层合并:
-
{"a": 1, "b": {"x": 10}}|{"b": {"y": 20}}→{"a": 1, "b": {"y": 20}}(整个"b"被替换,不是合并内部) - 如果左边字典有
None值,右边同 key 有值,会被正常覆盖;但若右边值为None,也会写入 - 不支持
dict | list等混合类型,会抛TypeError
用 ** 解包(兼容 Python 3.5+)
本质是构造新字典:{**d1, **d2},行为和 | 一致(右覆盖左),但可读性稍差,且无法用于表达式链(比如 {**d1, **d2, **d3} 可以,但不能直接 d1 | d2 | d3 那样链式写)。
容易踩的坑:
- 如果字典里有不可哈希的 key(比如列表),
**会直接报TypeError: unhashable type - 顺序敏感:
{**d2, **d1}是 d1 覆盖 d2,别写反了 - 空字典
{**{}}没问题,但{**None}会崩
用 update() 就地修改
修改左侧字典本身,不返回新对象(返回 None),适合明确想复用原字典内存的场景。
注意点:
- 别写成
d1 = d1.update(d2)—— 这会让d1变成None -
update()对嵌套字典同样只做浅层替换,不会递归合并 - 如果 d2 是
None或非 dict 类型(如 list),会报AttributeError或TypeError - 性能上,就地修改比生成新字典略快,但调试时容易因副作用难追踪
需要深度合并?得自己写或用第三方
标准库不提供深度合并(deep merge),比如两个字典都有 "user": {"name": "A"} 和 "user": {"age": 25},想得到 {"user": {"name": "A", "age": 25}}。
简单手写逻辑要点:
- 递归判断 value 类型:都是 dict 才继续合并,否则按“右覆盖”规则处理
- 要小心循环引用,否则无限递归
- 第三方库如
deepmerge或mergedict可用,但引入依赖前先确认是否真需要——多数业务场景一层合并就够
真正麻烦的是混合类型键、自定义对象作为 value、或合并时需做类型转换(比如把字符串数字转成 int),这些没法靠通用函数兜底,得在业务层加判断。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











