import collections import itertools # from jaraco.collections 3.5.1 class DictStack(list, collections.abc.Mapping): """ A stack of dictionaries that behaves as a view on those dictionaries, giving preference to the last. >>> stack = DictStack([dict(a=1, c=2), dict(b=2, a=2)]) >>> stack['a'] 2 >>> stack['b'] 2 >>> stack['c'] 2 >>> len(stack) 3 >>> stack.push(dict(a=3)) >>> stack['a'] 3 >>> set(stack.keys()) == set(['a', 'b', 'c']) True >>> set(stack.items()) == set([('a', 3), ('b', 2), ('c', 2)]) True >>> dict(**stack) == dict(stack) == dict(a=3, c=2, b=2) True >>> d = stack.pop() >>> stack['a'] 2 >>> d = stack.pop() >>> stack['a'] 1 >>> stack.get('b', None) >>> 'c' in stack True """ def __iter__(self): dicts = list.__iter__(self) return iter(set(itertools.chain.from_iterable(c.keys() for c in dicts))) def __getitem__(self, key): for scope in reversed(tuple(list.__iter__(self))): if key in scope: return scope[key] raise KeyError(key) push = list.append def __contains__(self, other): return collections.abc.Mapping.__contains__(self, other) def __len__(self): return len(list(iter(self)))