最近看到組內有小夥伴在處理在多個dict內順序查找元素的時候,用了ChainMap,有意思。場景: 當用戶輸入一個產品id的時候,你但願能正在出售的產品,或在已過時的產品中查找。python
你能夠實現:git
g_expire_products = { 1: {'name': 'nike shoes', 'price': 30}, 2: {'name': 'box', 'price': 2}, } g_on_sale_products = { 3: {'name': 'adidas shoes', 'price': 25}, 4: {'name': 'tee', 'price': 2}, } def get_product(id): return g_on_sale_products.get(id, g_expire_products.get(id))
若是是不止已過時產品,但願在其餘庫房的產品也能被查找,你可能還要在一個新的dict裏面查找。github
這不難實現,就是代碼看起來有點難看。
爲什麼不試下ChainMap,用ChainMap能夠這樣寫:app
g_products = ChainMap(g_on_sale_products, g_expire_products) def get_product(id): return g_products.get(id)
ChainMap能夠添加多個dict,至關於把你的if-else判斷作了抽象。ide
ChainMap源碼在這兒code
能夠看下__init__orm
def __init__(self, *maps): '''Initialize a ChainMap by setting *maps* to the given mappings. If no mappings are provided, a single empty dictionary is used. ''' self.maps = list(maps) or [{}] # always at least one map
這裏傳入多個dict後,多個dict放在maps裏,這裏maps傳的是多個dict的引用,也就是它沒有拷貝內存。內存
那麼它是如何查找key的,咱們來看下:get
def __missing__(self, key): raise KeyError(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__ def get(self, key, default=None): return self[key] if key in self else default def __contains__(self, key): return any(key in m for m in self.maps)
能夠看到,當經過dict[key]的時候,它是從self.maps裏的存的dict,從前日後找,初始化的時候,第一個dict先被查找,key不在第一個dict的時候,就會找下一個dict裏查找。源碼
不過它在修改的時候,是這樣作的
def __setitem__(self, key, value): self.maps[0][key] = value def __delitem__(self, key): try: del self.maps[0][key] except KeyError: raise KeyError('Key not found in the first mapping: {!r}'.format(key))
也就是你修改其中一個key的時候,它會在第一個dict裏面修改,刪除一個key時候也是。
因此通常使用ChainMap的時候,我以爲最好不要作修改,由於修改是基於你初始化的時候,傳入的dict的順序,每次若是初始化的時候,若是dict的順序不肯定,你每次就不能肯定會修改哪個dict。