Python Forum

Full Version: ChainMaps - Chaining multiple dictionaries
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
The collections module in the standard library provides the ChainMap class which joins multiple dictionaries to act as if it was a one large dictionary.
Consider the following example:
#import the ChainMap class
from collections import ChainMap

d1 = {'one': 1, 'two': 2, 'three': 3}
d2 = {'four': 4, 'five': 5, 'six': 6}
d3 = {'seven': 7, 'eight': 8, 'nine': 9}

chain = ChainMap(d1, d2, d3)

print(chain)
Output:
ChainMap({'one': 1, 'two': 2, 'three': 3}, {'four': 4, 'five': 5, 'six': 6}, {'seven': 7, 'eight': 8, 'nine': 9})
The resulting ChainMap object has a dictionary interface. When retrieving data, each dictionary is searched in turn, going from the first to the last.
#import the ChainMap class
from collections import ChainMap

d1 = {'one': 1, 'two': 2, 'three': 3}
d2 = {'four': 4, 'five': 5, 'six': 6}
d3 = {'seven': 7, 'eight': 8, 'nine': 9}

chain = ChainMap(d1, d2, d3)

print(chain['three'])
print(chain['five'])
print(chain['eight'])
print(chain['nine'])
Output:
3 5 8 9
As shown chainmap object acts as if it was a one long dictionary made from the individual dictionaries.
See More:
Thanks, interesting feature though I suspect it doesn't happen often, when one needs such an "aggregator". It would be luck to recollect about it in time :)

Also it is curious to investigate behavior of duplicate keys and key removal and reinserting

from collections import ChainMap

d1 = {'one': 1, 'two': 2, 'three': 3}
d2 = {'four': 4, 'five': 5, 'six': 6, 'three': 'drei'}
d3 = {'seven': 7, 'eight': 8, 'nine': 9}

chain = ChainMap(d1, d2, d3)

print(chain['three'])
print(chain['five'])
print(chain['eight'])
print(chain['nine'])
del chain['three']
print('three' in d1, 'three' in d2)
print(chain['three'])
chain['three'] = 'trois'
print('three' in d1, 'three' in d2)
it could be seen that insert works into the first dict, while duplicates simply shadow each other

P.S. now a kind of homework: how iteration over keys works? in which order? what if there are duplicates?
(Jun-23-2024, 05:48 AM)rodiongork Wrote: [ -> ]I suspect it doesn't happen often, when one needs such an "aggregator".
This can be useful when you want to alter temporarily a context, then restore the initial context. For example suppose that you are writing something on a sheet of paper and the context contains the color of the pen, initialy black and its width, initialy 1.
>>> def write(*args): # for illustrative purpose
...     pass
... 
>>> from collections import ChainMap
>>> c = ChainMap({'width': 1, 'color': 'black'}) # initial context
>>> write('Hello world!', c) # write something 
>>> 
>>> c = c.new_child({'color': 'red'})  # temporarily set the color
>>> c['color']
'red'
>>> write('Nice weather today!', c) # write in red
>>> c = c.parents # restore previous context
>>> c['color']
'black'
This usage is similar to the operators gsave and grestore in the Postscript language. gsave saves the current « graphic context » which contains various parameters. Then one can update the context temporarily, and the next call to grestore restores the initial graphic context.

(Jun-23-2024, 05:48 AM)rodiongork Wrote: [ -> ]now a kind of homework: how iteration over keys works? in which order? what if there are duplicates?
Hint: start by reading the code of collections/__init__.py