collections.ChainMap 是 Python 标准库中一个非常实用的工具,它将多个字典或映射组合成一个单一的、可更新的视图。当查找一个键时,ChainMap 会按照传入字典的顺序依次查找,返回第一个找到的键对应的值。这在需要按优先级合并配置或环境变量等场景下非常有用。
考虑以下两个字典 a 和 b:
a = {'123': {'player': 1, 'opponent': 2}, '18': {'player': 10, 'opponent': 12} } b = {'123': {'winner': 1}, '180': {'winner': 2} }
如果直接使用 ChainMap(a, b) 并尝试将其转换为字典,我们会发现 ChainMap 默认的行为是浅层合并。对于相同的顶级键,它会优先使用第一个字典中的值,而不会尝试合并嵌套的字典:
from collections import ChainMap print(dict(ChainMap(a, b))) # 输出: {'123': {'player': 1, 'opponent': 2}, '180': {'winner': 2}, '18': {'player': 10, 'opponent': 12}}
可以看到,键 '123' 的值直接取自 a,b 中 '123' 下的 {'winner': 1} 被完全忽略了。这与我们期望的深度合并结果,即 '123' 下的字典应合并为 {'player': 1, 'opponent': 2, 'winner': 1},相去甚远。
立即学习“Python免费学习笔记(深入)”;
要实现对嵌套字典的深度合并,我们需要扩展 ChainMap 的行为,使其在遇到嵌套字典时能够递归地进行合并。这可以通过重写 DeepChainMap 类的 __getitem__ 方法来实现。当 ChainMap 尝试获取一个键的值时,如果该值本身是一个字典,我们则递归地为这个嵌套字典创建另一个 DeepChainMap 实例,从而实现深度合并。
以下是 DeepChainMap 的实现:
from collections import ChainMap class DeepChainMap(ChainMap): """ ChainMap 的变体,支持对嵌套字典的深度合并。 当获取一个键的值时,如果该值是字典,则递归地合并所有映射中该键对应的字典。 """ def __getitem__(self, key): # 收集所有映射中存在给定键的值 values = (mapping[key] for mapping in self.maps if key in mapping) try: # 获取第一个找到的值 first = next(values) except StopIteration: # 如果所有映射中都不存在该键,则调用父类的 __missing__ 方法(通常会抛出 KeyError) return self.__missing__(key) # 如果第一个值是字典,则递归地为所有找到的字典值创建 DeepChainMap if isinstance(first, dict): # 注意:这里将 first 放在第一个,以确保其内容优先, # 并且后续的 values 会按 ChainMap 的顺序进行合并 return self.__class__(first, *values) # 如果不是字典,直接返回第一个找到的值 return first def __repr__(self): # 为了更清晰的表示,将 DeepChainMap 转换为普通字典的字符串表示 return repr(dict(self))
__repr__ 方法被重写是为了提供一个更友好的字符串表示。默认情况下,ChainMap 的 repr 会显示其内部的 maps 列表,这对于调试和理解 DeepChainMap 的最终状态不太直观。通过将其转换为 dict(self) 再进行 repr,我们可以直接看到合并后的字典结构,就像一个普通的字典一样。
现在,我们可以使用自定义的 DeepChainMap 来实现我们最初的目标:
# 重新定义原始字典 a = {'123': {'player': 1, 'opponent': 2}, '18': {'player': 10, 'opponent': 12} } b = {'123': {'winner': 1}, '180': {'winner': 2} } # 使用 DeepChainMap 进行合并 merged_map = DeepChainMap(a, b) print(merged_map) # 预期输出: {'123': {'winner': 1, 'player': 1, 'opponent': 2}, '180': {'winner': 2}, '18': {'player': 10, 'opponent': 12}} # 转换为普通字典以进行进一步操作(如果需要) final_dict = dict(merged_map) print(final_dict) # 输出: {'123': {'winner': 1, 'player': 1, 'opponent': 2}, '180': {'winner': 2}, '18': {'player': 10, 'opponent': 12}}
从输出可以看出,对于键 '123',嵌套字典 { 'player': 1, 'opponent': 2 } 和 { 'winner': 1 } 已经被成功合并为一个完整的字典 { 'player': 1, 'opponent': 2, 'winner': 1 }。同时,非重叠的键 '18' 和 '180' 也被正确保留。
通过自定义 DeepChainMap,我们成功扩展了 collections.ChainMap 的功能,使其能够处理更复杂的深度合并需求,为 Python 开发者提供了更强大的字典操作工具。
以上就是使用 ChainMap 实现 Python 字典的深度合并的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号