如何更新含嵌套字典列表的嵌套字典(列表元素顺序无关)
深度嵌套字典(含嵌套字典的列表)的正确更新实现
问题背景
我有多个不同深度的嵌套字典,具备以下特性:
- 字典可包含内部嵌套进一步字典的列表;
- 字典也可包含仅存值的“叶子列表”;
- 列表元素顺序无关。
示例数据
base_d = {'level 1' : {'level 2': [{'level 3': [1,2,3], 'level 4': {'level 6': 'replace_me'} } ] } } update_d = {'level 1' : {'level 2': [{'level 4': {'level 6': 'new_value','level 7':456},'level 5':123 , 'level 3': [1,2,3,4] }] } }
预期更新结果
希望用update_d更新base_d后得到:
new_d = {'level 1' : {'level 2': [{'level 3': [1,2,3,4], 'level 4': {'level 6': 'new_value'} } ] } }
尝试过的方法及问题
1. pydantic.utils.deep_update
使用该方法得到的结果不符合预期:
from pydantic.utils import deep_update result = deep_update(base_d, update_d) # 输出: {'level 1': {'level 2': [{'level 4': {'level 6': 'new_value', 'level 7': 456}, 'level 5': 123, 'level 3': [1, 2, 3, 4]}]}}
问题:保留了update_d中新增的level 7和level 5,但实际预期只更新原有键对应的值,不新增未在base_d中出现的键。
2. 自定义更新函数
import collections def update(orig_dict, new_dict): for key, val in new_dict.iteritems(): if isinstance(val, collections.abc.Mapping): tmp = update(orig_dict.get(key, { }), val) orig_dict[key] = tmp elif isinstance(val, list): orig_dict[key] = (orig_dict.get(key, []) + val) else: orig_dict[key] = new_dict[key] return orig_dict
问题:无法正确处理列表内部的嵌套字典更新逻辑。
解决方案
要实现符合预期的更新,需针对列表中的嵌套字典做特殊处理:识别列表中结构匹配的字典(通过键集合交集判断),对其进行深度更新而非直接替换/合并列表;同时,字典更新仅覆盖原有键的值,不新增原字典中不存在的键。
以下是实现函数:
import collections.abc def deep_update_filtered(orig, update): if isinstance(orig, collections.abc.Mapping) and isinstance(update, collections.abc.Mapping): # 仅遍历原字典已存在的键,避免新增未定义的键 for key in orig: if key in update: orig[key] = deep_update_filtered(orig[key], update[key]) return orig elif isinstance(orig, list) and isinstance(update, list): # 处理含嵌套字典的列表:匹配同结构字典进行更新 for orig_item in orig: for update_item in update: if isinstance(orig_item, collections.abc.Mapping) and isinstance(update_item, collections.abc.Mapping): # 存在共同键则视为同一实体,递归更新 if set(orig_item.keys()) & set(update_item.keys()): deep_update_filtered(orig_item, update_item) # 处理叶子列表:合并去重(因顺序无关) if not any(isinstance(item, collections.abc.Mapping) for item in orig + update): orig[:] = list(set(orig + update)) return orig else: # 基础类型直接用更新值替换 return update
测试验证
base_d = {'level 1' : {'level 2': [{'level 3': [1,2,3], 'level 4': {'level 6': 'replace_me'} } ] } } update_d = {'level 1' : {'level 2': [{'level 4': {'level 6': 'new_value','level 7':456},'level 5':123 , 'level 3': [1,2,3,4] }] } } result = deep_update_filtered(base_d, update_d) print(result) # 输出与预期一致: {'level 1': {'level 2': [{'level 3': [1, 2, 3, 4], 'level 4': {'level 6': 'new_value'}}]}}
函数说明
- 字典处理:仅遍历原字典已有的键,用更新字典对应键的值递归更新,不会新增原字典中不存在的键;
- 列表处理:
- 嵌套字典列表:通过键交集匹配同实体字典,递归更新内部结构;
- 叶子列表:合并两个列表并去重(因顺序无关);
- 基础类型:直接用更新值替换原值。
内容的提问来源于stack exchange,提问作者Kspr
相关产品推荐
相关产品推荐

