Encapsulates lookups into a series of namespaces.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | import UserDict
class Chainmap(UserDict.DictMixin):
"""Combine multiple mappings for sequential lookup.
For example, to emulate Python's normal lookup sequence:
import __builtin__
pylookup = Chainmap(locals(), globals(), vars(__builtin__))
"""
def __init__(self, *maps):
self._maps = maps
def __getitem__(self, key):
for mapping in self._maps:
try:
return mapping[key]
except KeyError:
pass
raise KeyError(key)
if __name__ == "__main__":
d1 = {'a':1, 'b':2}
d2 = {'a':3, 'd':4}
cm = Chainmap(d1, d2)
assert cm['a'] == 1
assert cm['b'] == 2
assert cm['d'] == 4
try:
print cm['f']
except KeyError:
pass
else:
raise Exception('Did not raise KeyError for missing key')
assert 'a' in cm and 'b' in cm and 'd' in cm
assert cm.get('a', 10) == 1
assert cm.get('b', 20) == 2
assert cm.get('d', 30) == 4
assert cm.get('f', 40) == 40
|
The underlying mapping need only define __getitem__ and raise KeyError when a key is not found.
This is a general purpose routine applicable in many contexts. Something similar was used to implement string.Template in Py2.4.
Tags: oop
Why not create a new dictionary which is the "update" of all?
[Miki]
The update() approach works great in some situations. It is an O(n) operation that copies all of the dictionaries. In contrast, chainmap() is an O(1) step that effectively creates a view of the component mappings. Besides being fast, a view confers other advantages such as the combined mapping always reflecting any updates to the component mappings.
The chainmap() approach in used in the standard library's implementation of string.Template(). It was also used to dramatically speed-up the configparser module.