**解包在函数调用中是关键字参数展开,在字典字面量中是浅层键值覆盖合并;它总生成新字典,不修改原字典,不递归处理嵌套,同名键按从左到右顺序被后项覆盖。

Python 3.5+ 中 ** 解包字典的底层行为是什么
双星号 ** 在函数调用中是「关键字参数解包」,不是「字典合并」本身。它把字典的键值对展开成 key=value 形式传给函数;只有当目标函数接收 **kwargs 时,这些值才被收集为新字典。直接写 {**dict1, **dict2} 是字典字面量语法糖,由解释器在构建时按顺序覆盖键——后出现的同名键会覆盖前面的。
为什么 {**a, **b} 能合并字典但不能原地修改
这种写法生成的是一个全新字典对象,a 和 b 本身完全不变。常见误操作是以为它类似 dict.update(),结果发现原字典没变,或者误用于需要可变对象的场景(比如作为类实例属性反复更新)。
-
a = {'x': 1}; b = {'y': 2}; c = {**a, **b}→c是新字典,a和b不受影响 - 若需原地合并,仍得用
a.update(b)或a |= b(Python 3.9+) - 嵌套字典不会递归合并,
{**{'a': {'x': 1}}, **{'a': {'y': 2}}}得到{'a': {'y': 2}},不是{'a': {'x': 1, 'y': 2}}
多个字典解包时的覆盖顺序和空字典处理
从左到右依次解包,右边的同名键覆盖左边的。空字典 {} 可安全参与,不改变结果,但要注意它仍会触发一次解包开销。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
-
{**{'a': 1, 'b': 2}, **{'b': 3, 'c': 4}}→{'a': 1, 'b': 3, 'c': 4} -
{**d1, **{}, **d2}等价于{**d1, **d2},但多一次空字典遍历 - 若某个字典含不可哈希键(如列表),解包时立即抛出
TypeError: unhashable type,错误位置指向该字典,不是最终构造处
和 collections.ChainMap、| 操作符的关键区别
{**a, **b} 是一次性浅拷贝合并;ChainMap 是视图式链式查找(不复制数据,只查第一个有该键的映射);a | b(Python 3.9+)语义等价于 {**a, **b},但返回类型保留左操作数类型(如 OrderedDict | dict 返回 OrderedDict)。
- 性能上:
{**a, **b}和a | b接近,都需遍历所有键值对;ChainMap(a, b)构造极快,但每次__getitem__多一层查找开销 - 内存:解包合并产生新字典,
ChainMap几乎零额外内存 - 兼容性:
**解包从 Python 3.5 支持,|仅 3.9+,ChainMap从 2.7/3.2 就存在
真正容易被忽略的是:所有这三种方式都只做浅层操作,对嵌套结构完全无感。如果业务逻辑依赖深层合并,必须自己实现或引入 deepmerge 类库——靠 ** 解包解决不了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










