1import collections 2import itertools 3 4 5# from jaraco.collections 3.5.1 6class DictStack(list, collections.abc.Mapping): 7 """ 8 A stack of dictionaries that behaves as a view on those dictionaries, 9 giving preference to the last. 10 11 >>> stack = DictStack([dict(a=1, c=2), dict(b=2, a=2)]) 12 >>> stack['a'] 13 2 14 >>> stack['b'] 15 2 16 >>> stack['c'] 17 2 18 >>> len(stack) 19 3 20 >>> stack.push(dict(a=3)) 21 >>> stack['a'] 22 3 23 >>> set(stack.keys()) == set(['a', 'b', 'c']) 24 True 25 >>> set(stack.items()) == set([('a', 3), ('b', 2), ('c', 2)]) 26 True 27 >>> dict(**stack) == dict(stack) == dict(a=3, c=2, b=2) 28 True 29 >>> d = stack.pop() 30 >>> stack['a'] 31 2 32 >>> d = stack.pop() 33 >>> stack['a'] 34 1 35 >>> stack.get('b', None) 36 >>> 'c' in stack 37 True 38 """ 39 40 def __iter__(self): 41 dicts = list.__iter__(self) 42 return iter(set(itertools.chain.from_iterable(c.keys() for c in dicts))) 43 44 def __getitem__(self, key): 45 for scope in reversed(tuple(list.__iter__(self))): 46 if key in scope: 47 return scope[key] 48 raise KeyError(key) 49 50 push = list.append 51 52 def __contains__(self, other): 53 return collections.abc.Mapping.__contains__(self, other) 54 55 def __len__(self): 56 return len(list(iter(self))) 57