57 lines
1.3 KiB
Python
57 lines
1.3 KiB
Python
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)))
|