本文介绍如何将一个字典(源)有选择地合并到另一个结构相同但含 none 值的字典(目标)中:仅当源字典中某键的值不为 none 时,才用该值更新目标字典中同名键的值,其余键值对保持不变。
聊一个Python数据处理里很常见的需求:做字典合并的时候,不是一股脑全覆盖,而是有条件地挑着来。比如你手上有个目标字典,里面有些值是None(等待填充的占位符),现在来了一个源字典,你想用它里面实实在在的值去更新目标,但源字典里也带None——那就要跳过这些None,只把非None的拿过来用。听起来简单,但写出来却容易踩坑。
核心诉求其实就一句话:以目标字典的现有结构为基准,只允许源字典中非None的值精准覆盖同名键,不强加新键,也不删已有键,更不把有效数据给覆盖掉。
✅ 推荐实现方式(Python 3.9+)
Python 3.9 引入的字典合并运算符 |= 配合字典推导式,可以说是最优雅的解法:
dict1 = {"a": 0.0, "b": None}
dict2 = {"a": None, "b": 2.2}
# 仅合并 dict1 中 value 不为 None 的键值对
dict2 |= {k: v for k, v in dict1.items() if v is not None}
print(dict2) # {'a': 0.0, 'b': 2.2}
? 注意:判断条件用
v is not None而不是not v,后者会把 0.0、False、[] 这类 falsy 值也过滤掉——但人家明明是有意义的“空值”,不该被跳过。
? 兼容旧版本(Python < 3.9)
版本不够新也没关系,换成 update() 方法,逻辑完全一致:
dict2.update({k: v for k, v in dict1.items() if v is not None})
⚠️ 关键注意事项
- 要不要引入新键? 上面的写法默认允许源字典里的新键出现在目标字典中。如果想要严格限制——只更新目标字典里已有的键,不新增——那就加个
and k in dict2条件:dict2 |= {k: v for k, v in dict1.items() if v is not None and k in dict2} - 源字典保持原样:所有操作都在目标字典上完成,源字典纹丝不动。
- 只有 None 被跳过:0、空字符串、空列表、False 这些值,只要不是 None,通通视为有效数据,参与合并。
- 嵌套字典需要递归处理:上面这套方案只适用于扁平字典。如果结构里套着字典,得用递归合并(比如
deepmerge库,或者自己写个merge_dict_recursive)。
✅ 验证示例
# 示例 1
dict1 = {"a": 0.0, "b": None}
dict2 = {"a": None, "b": 2.2}
dict2 |= {k: v for k, v in dict1.items() if v is not None}
assert dict2 == {"a": 0.0, "b": 2.2}
# 示例 2
dict1 = {"a": 0.0, "b": 5.5}
dict2 = {"a": None, "b": 2.2}
dict2 |= {k: v for k, v in dict1.items() if v is not None}
assert dict2 == {"a": 0.0, "b": 5.5}
这种方式简洁、高效、语义清晰,处理“优先级覆盖 + None 跳过”这类合并任务,算得上标准的实践写法了。