ChainMap提供了一种多个字典整合的方式,它没有去合并这些字典,而是将这些字典放在一个 maps (一个列表)里,内部实现了很多 dict 的方法,大部分 dict 的方法,ChainMap 都能使用。
ChainMap在获取一个key的值时,会遍历 maps ,一旦在其中一个 字典里找到了这个 key ,便停止寻找,源码如下:
def __getitem__(self, key): for mapping in self.maps: try: return mapping[key] # can't use 'key in mapping' with defaultdict except KeyError: pass return self.__missing__(key) # support subclasses that define __missing__
例子:
a = {'x': 1, 'z': 3 } b = {'y': 2, 'z': 4 }
from collections import ChainMap c = ChainMap(a,b) print(c['x']) # Outputs 1 (from a) print(c['y']) # Outputs 2 (from b) print(c['z']) # Outputs 3 (from a)
当设置 ChainMap 的某个key时,只能在第一个字典里寻找这个key,找到则更新,没找到则设置,源码如下:
def __setitem__(self, key, value): self.maps[0][key] = value
例:
c['z'] = 5
c['g'] = 2
print(a) # output: {'x': 1, 'z': 5, 'g': 5 }
print(b) # output: {'y': 2, 'z': 4}
删除某个key时,也是一样,只会在第一个dict中寻找这个key,如果没有找到会报错 KeyError
其他方法:
new_child(self, m=None):
从左边加入,若 m=None,则在左边加入一个空的 dict
源码如下:
def new_child(self, m=None): # like Django's Context.push() '''New ChainMap with a new map followed by all previous maps. If no map is provided, an empty dict is used. ''' if m is None: m = {} return self.__class__(m, *self.maps)
parents(self):
删除左边的 dict 后,返回一个新的ChainMap。
def parents(self): # like Django's Context.pop() 'New ChainMap from maps[1:].' return self.__class__(*self.maps[1:])
作为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 >>>
>>> a['x'] = 13 >>> merged['x'] 1
ChainMap 使用原来的字典,不会发生上面的情况:
>>> a = {'x': 1, 'z': 3 } >>> b = {'y': 2, 'z': 4 } >>> merged = ChainMap(a, b) >>> merged['x'] 1 >>> a['x'] = 42 >>> merged['x'] # Notice change to merged dicts 42 >>>