合并多个字典或映射
ChainMap
假设有多个字典或者映射,需求是将这些字典或者映射,从逻辑上合并为一个单一的映射后执行其他操作,例如查找值或者检查某些键是否存在。
假如有如下两个字典:
>>> a = {'x': 1, 'z':3}
>>> b = {'y': 2, 'z': 4}
假设现在的需求是在两个字典中执行查询操作,先在字典 a
中查找,若查询无结果,再在 b
中查找。这里有个解决方案就是使用 collections
模块中提供的 ChainMap
类。示例如下:
>>> from collections import ChainMap
>>> c = ChainMap(a, b)
>>> c['x'] # 从 a 中输出
1
>>> c['y'] # 从 b 中输出
2
>>> c['z'] # 从 a 中输出
3
ChainMap
作用是将多个字典或者其他映射组合在一起,创建一个单独的可更新的视图。这里的意思是,原多个字典并非真的合并在一起,是 ChainMap
类在内部创建一个容纳这些字典列表,同时重新定义一些常见的字典操作来遍历这个列表。以下是使用 ChainMap
后的一部分字典操作:
>>> len(c)
3
>>> list(c.keys())
['z', 'y', 'x']
>>> list(c.values())
[3, 2, 1]
这里特别提及下,如果出现重复键,会返回第一次出现的映射值。因此,上面例子中, c['z']
返回的值总是对应字典 a
,而不是字典 b
。
同时,对于字典的更像或者删除操作也同样是影响列表中的第一个字典。示例如下:
>>> c['z'] = 10
>>> c['w'] = 60
>>> del c['x']
>>> a
{'z': 10, 'w': 60}
>>> del c['y']
Traceback (most recent call last):
...
KeyError: "Key not found in the first mapping: 'y'"
new_child() 和 parents
ChainMap
还有个 new_child
方法和 parents
属性。
下面是两者的一些使用方法:
>>> values = ChainMap()
>>> values['x'] = 1
>>> # 添加一个新的映射
... values = values.new_child()
>>> values['x'] = 2
>>> # 添加一个新的映射
... values = values.new_child()
>>> values['x'] = 3
>>> values
ChainMap({'x': 3}, {'x': 2}, {'x': 1})
>>> values['x']
3
>>> # 丢弃映射
... values = values.parents
>>> values['x']
2
>>> values = values.parents
>>> values['x']
1
>>> values
ChainMap({'x': 1})
从上面的例子中可以看到,new_child()
方法返回一个新的 ChainMap
类,包含一个新映射,后面跟随当前实例的全部映射。这个方法用于创建子上下文,不改变任何父映射的值。
parents
属性返回一个新的 ChainMap
包含所有的当前实例的映射,除了第一个。这样可以在搜索的时候跳过第一个映射。
作为 ChainMap
的替代,可以考虑 update()
方法将两个字典合并,示例如下:
>>> a = {'x': 1, 'z': 3}
>>> b = {'y': 2, 'z': 4}
>>> merged = dict(b)
>>> merged.update(a)
>>> merged['x']
1
>>> merged['y']
2
>>> merged['z']
3
>>>
update()
方法同样能够实现需求,但是,它需要新建一个完全不同的字典对象(或者破坏现有的字典结构),还有一点是,原字典所做的更像,不会反应到新的字典中。示例如下:
>>> a['x'] = 13
>>> merged['x']
1
对字典 a
中的 x
进行更改,合并后的字典并没有发生改变。
ChainMap
使用原来的字典,它自己不创建新的字典。所以不会出现上面的情况,示例如下:
>>> a = {'x': 1, 'z': 3}
>>> b = {'y': 2, 'z': 4}
>>> merged = ChainMap(a, b)
>>> merged['x']
1
>>> a['x'] = 13
>>> merged['x'] # 这里可以注意到用 ChainMap 合并的字典,值同样发生了改变
13
以上就是本篇的主要内容。