python 3.12 推荐使用 | 和 |= 合并字典:| 创建新字典且语义清晰,|= 就地更新并支持链式调用;** 简洁但要求映射类型且不安全;update() 就地修改、灵活但有副作用。

双星号 ** 合并字典:语法简洁但有隐含限制
Python 3.12 中用 ** 解包合并两个字典,写法最短:{**dict_a, **dict_b}。它本质是构造新字典,dict_b 的键值会覆盖 dict_a 中同名键的值。
但要注意:所有被解包的对象必须是映射类型(dict、Mapping 子类),不能是 None 或普通可迭代对象;且不支持嵌套合并——遇到嵌套字典时直接覆盖,不会递归合并。
常见错误现象:TypeError: 'NoneType' object is not a mapping,常出现在某个字典变量为 None 却直接 **d 解包。
- 若需安全解包,先做判断:
{**dict_a, **(dict_b or {})} - 若
dict_b可能为None或非字典类型,建议封装成函数做类型检查 - 性能上,
**构造新字典比update()略慢(尤其大字典),因涉及多次哈希计算和内存分配
dict.update() 合并:就地修改,适合流程中复用原字典
dict.update() 不创建新字典,而是把第二个字典的键值对“注入”到第一个字典中。适用于需要持续累加键值、或内存敏感场景。
它接受多种输入:字典、关键字参数、iterable(如 [('a', 1), ('b', 2)]),灵活性更高。但副作用明显——调用后原字典已变,若后续还需原始数据,必须提前 copy()。
常见错误现象:dict_a.update(dict_b) 执行后 dict_a 被改,但误以为返回了新字典(实际返回 None)。
- 想链式调用?不行:
dict_a.update(dict_b).keys()会报AttributeError - 要保留原字典又想就地逻辑?写成:
result = dict_a.copy(); result.update(dict_b) - Python 3.12 对
update()没行为变更,但传入非映射对象时仍抛TypeError,不是静默忽略
Python 3.12 新增的 | 和 |=:语义清晰,推荐优先使用
从 Python 3.9 起引入、3.12 依然适用的合并操作符:| 创建新字典,|= 就地更新。它们比 ** 更明确表达“合并”意图,也比 update() 更少歧义。
dict_a | dict_b 等价于 {**dict_a, **dict_b},但更易读;dict_a |= dict_b 等价于 dict_a.update(dict_b),但返回的是更新后的字典本身(支持链式),且只接受映射类型。
容易踩的坑:| 不支持 None 或列表等非映射类型,报错信息比 ** 更直白:TypeError: unsupported operand type(s) for |: 'dict' and 'NoneType'。
- 安全写法:
dict_a | (dict_b or {}),但注意or会把空字典以外的 falsy 值(如{})也转成空字典 - 若需深度合并,这三个方法都不行——得用
deepcopy+ 递归逻辑,或第三方库如deepmerge -
|=在多线程中不安全,和update()一样,没有原子性保证
选哪个?看你的核心约束是什么
如果追求代码可读性和未来兼容性,| 是首选;如果维护旧项目(** 是折中选择;如果已在修改一个字典且确定不再需要原状态,update() 或 |= 都可以,但后者能返回值,更利于表达式上下文。
真正容易被忽略的是嵌套结构处理——无论用哪种方式,都只是浅合并。比如 dict_a = {'x': {'a': 1}} 和 dict_b = {'x': {'b': 2}} 合并后,'x' 的值永远是后者整个字典,不会变成 {'a': 1, 'b': 2}。这种需求必须单独实现逻辑,没捷径。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











