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 >>>