_collections.py 1.3 KB

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