ChainMap is one of the most commonly used class provided by the collections module. collections module in Python provides specialized container data types that extend the capabilities of built-in data structures like lists, dictionaries, and tuples. These container data types are designed to make it easier to manage and manipulate data in specific and more efficient ways.
ChainMap
In Python, ChainMap class is part of the collections module and allows us to group multiple dictionaries or mappings into a single view. ChainMap in short is called as collection of dictionaries. It is particularly useful when we want to search through multiple dictionaries as if they were a single dictionary.
Syntax to create ChainMap object:
chainMap_object = collections.ChainMap(dict_1, dict_2, .... , dict_N). This can also be represented as => collections.ChainMap(*dictionaries)
collectionsis a module in Python.ChainMapclass is part ofcollectionsmodule. We need to importcollectionsmodule to useChainMapclass in our program.ChainMap()is theChainMapclass constructor*dictionariesis the group of dictionaries to be as an argument. We can multiple dictionaries as the same time.chainMap_objectis the object returned
ChainMap Properties
There are many properties of Chainmap collection.
- Order of dictionaries in
ChainMapobject is very important. - Search Order –
ChainMapsearches for keys in the dictionaries in the order they were provided. The first mapping in theChainMaphas the highest priority. If a key is found in the first dictionary, its value is returned immediately, and the search stops. If not, the search continues through the subsequent dictionaries. - Dynamic View –
ChainMapprovides a dynamic view of the dictionaries. If any of the original dictionaries are updated or changed, those changes will be reflected in theChainMapobject. - Modifications – Assigning a value to a key in a
ChainMapwill update the first dictionary in which the key is found. If the key does not exist in any of the dictionaries, it will be added to the first dictionary in the chain. - Adding New Mappings – New dictionary to the front of the
ChainMapcan be added using thenew_child()method. This creates a newChainMapwith the new dictionary as the first element, leaving the originalChainMapunchanged. - Accessing Dictionaries –
mapsattribute of aChainMapreturns a list of the dictionaries it contains. We can access, modify, or reorder these dictionaries if needed. - Key Deletion – Deleting a key from a
ChainMapwill only remove the key from the first dictionary in which it is found. If the key is not found in the first dictionary, aKeyErroris raised. - Read-only View –
ChainMapprovides a unified view of multiple dictionaries, it does not merge the dictionaries. Each dictionary remains distinct, and no data is copied. This makesChainMapmemory-efficient, especially when dealing with large datasets or numerous dictionaries. ChainMapis useful when we have a series of dictionaries where earlier ones can override later ones. This is often the case with layered configuration systems (e.g., command-line arguments, environment variables, and default settings).- Iteration – Iterating over a
ChainMapyields keys from the first dictionary that contains them, preserving the order of the dictionaries. Duplicate keys in later dictionaries are ignored during iteration. - Compatibility –
ChainMapworks with any mapping type, not just dictionaries. We can include any object that implements the mapping interface (supports key-value pairs) in aChainMap.
ChainMap Object
To create ChainMap object, we need to import it from the collections module. We can create an empty ChainMap object OR a ChainMap object by passing in two or more dictionaries. Order of dictionaries is very important. The dictionaries are searched in the order they are passed.
Empty ChainMap Object
from collections import ChainMap # Import ChainMap from collections module
# create empty ChainMap
print("create empty ChainMap")
empty_chain_map = ChainMap() # Use ChainMap() constructor
print(empty_chain_map)
print(type(empty_chain_map)) # Print type of ChainMap object
In this program, we have imported ChainMap from collections module and we are using ChainMap() constructor, without any dictionary to create an empty ChainMap object.
Program Output
create empty ChainMap
ChainMap({})
<class 'collections.ChainMap'>
Empty ChainMap({}) is created and type of this object is <class 'collections.ChainMap'>.
ChainMap Object with Dictionaries
We can group multiple dictionaries or other mappings (key-value pairs) together to create a single, unified view of Chainmap object.
# Chainmap object with dictionaries
print("Chainmap object with dictionaries")
from collections import ChainMap # Import Chainmap from collections module
training_dict = {"1": "Shbytes", "2": "Online", "3": "Training"}
courses_dict = {"c1": "Python", "c2": "AWS", "c3": "Azure"}
dicts_chain_map = ChainMap(training_dict, courses_dict) # Use Chainmap() constructor with dictionaries
print(dicts_chain_map)
print(type(dicts_chain_map))
In this program, we have imported ChainMap from collections module and we are using ChainMap() constructor, with two dictionaries to create a ChainMap object.
Program Output
Chainmap object with dictionaries
ChainMap({'1': 'Shbytes', '2': 'Online', '3': 'Training'}, {'c1': 'Python', 'c2': 'AWS', 'c3': 'Azure'})
<class 'collections.ChainMap'>
ChainMap with two dictionary chain is created and type of this object is <class 'collections.ChainMap'>.
new_child() method – add child at front of ChainMap
We can add a new dictionary or mapping (key-value pair) to the front of the ChainMap using the new_child() method.
- Use
new_child()method to add an empty dictionary or to add a dictionary with elements. - A new
ChainMapobject is created, with the new dictionary as the first element. new_child()method does not make any change in originalChainMapobject.
Add empty child at front of ChainMap
# new_child() - add new empty child map at front of ChainMap
print("new_child() - add new empty child map at front of ChainMap")
from collections import ChainMap
training_dict = {"1": "shbytes", "2": "Online", "3": "Training"}
courses_dict = {"c1": "Python", "c2": "AWS", "c3": "Azure"}
shbytes_chain_map = ChainMap(training_dict, courses_dict)
print(shbytes_chain_map)
new_shbytes_chain_map = shbytes_chain_map.new_child() # Added new child at front of ChainMap object
print(new_shbytes_chain_map)
In this program, we have imported ChainMap class from collections module. Then we create a ChainMap object shbytes_chain_map with two dictionaries. We are using shbytes_chain_map.new_child() to add a new child at the front of the ChainMap object. This will create a new ChainMap object new_shbytes_chain_map without making change change to original object shbytes_chain_map.
Program Output
new_child() - add new empty child map at front of ChainMap
# original ChainMap object
ChainMap({'1': 'shbytes', '2': 'Online', '3': 'Training'}, {'c1': 'Python', 'c2': 'AWS', 'c3': 'Azure'})
# new ChainMap object with empty dictionary as its first element
ChainMap({}, {'1': 'shbytes', '2': 'Online', '3': 'Training'}, {'c1': 'Python', 'c2': 'AWS', 'c3': 'Azure'})
From the output of this program, we have new ChainMap object with empty dictionary as its first element.
Add dictionary with elements as new child at front of ChainMap
#new_child(map) - add dictionary as new child map at front of ChainMap
print("new_child(map) - add dictionary as new child map at front of ChainMap")
from collections import ChainMap
training_dict = {"1":"shbytes","2":"Online","3":"Training"}
courses_dict = {"c1":"Python","c2":"AWS","c3":"Azure"}
shbytes_chainmap = ChainMap(training_dict, courses_dict) # create a ChainMap object
print(shbytes_chainmap)
# Added dictionary with elements as new child at front of ChainMap object
level_shbytes_chainmap = shbytes_chainmap.new_child({"l1":"intermediate","l2":"expert"})
print(level_shbytes_chainmap)
In this program, we have imported ChainMap class from collections module. Then we create a ChainMap object shbytes_chainmap with two dictionaries. We are using shbytes_chainmap.new_child({"l1":"intermediate","l2":"expert"}) to add a dictionary as new child at the front of the ChainMap object. This will create a new ChainMap object level_shbytes_chainmap without making change change to original object shbytes_chainmap.
Program Output
new_child(map) - add dictionary as new child map at front of ChainMap
# original ChainMap object
ChainMap({'1': 'shbytes', '2': 'Online', '3': 'Training'}, {'c1': 'Python', 'c2': 'AWS', 'c3': 'Azure'})
# new ChainMap object with dictionary elements as its first element
ChainMap({'l1': 'intermediate', 'l2': 'expert'}, {'1': 'shbytes', '2': 'Online', '3': 'Training'}, {'c1': 'Python', 'c2': 'AWS', 'c3': 'Azure'})
From the output of this program, new ChainMap object has dictionary {'l1': 'intermediate', 'l2': 'expert'} added as its first element.
maps attribute – access ChainMap Mappings
To access the ChainMap mappings, we can use maps attribute of a ChainMap. maps attribute returns a list of the dictionaries in the ChainMap object. This can be used to access, modify, or reorder these dictionaries.
from collections import ChainMap
# maps - returns list of maps in ChainMap
print("maps - returns list of maps in ChainMap")
training_dict = {"1": "shbytes", "2": "Online", "3": "Training"}
courses_dict = {"c1": "Python", "c2": "AWS", "c3": "Azure"}
shbytes_chain_map = ChainMap(training_dict, courses_dict)
print(shbytes_chain_map)
print(shbytes_chain_map.maps) # Access mappings using maps attribute
Program Output
maps - returns list of maps in ChainMap
ChainMap({'1': 'shbytes', '2': 'Online', '3': 'Training'}, {'c1': 'Python', 'c2': 'AWS', 'c3': 'Azure'})
[{'1': 'shbytes', '2': 'Online', '3': 'Training'}, {'c1': 'Python', 'c2': 'AWS', 'c3': 'Azure'}]
maps attribute returns a list of dictionaries or mappings (key-value pairs) from the given ChainMap object.
parents attribute – all ChainMap mappings except first
We can access all dictionaries or mappings (key-value pair) except first, from ChainMap object using the parents attribute.
- Use
parentsattribute to get all dictionaries or mappings (key-value pair) except first. - A new
ChainMapobject is created, which will not have first dictionary. parentsattribute does not make any change in originalChainMapobject.
#return new ChainMap containing all of the maps in current instance except the first one
print("return new ChainMap containing all of the maps in current instance except the first one")
from collections import ChainMap
dict_1 = {1: 'a', 2: 'b'}
dict_2 = {3: 'c', 4: 'd'}
dict_3 = {5: 'e', 6: 'f'}
shbytes_chainmap = ChainMap(dict_1, dict_2, dict_3)
parent_shbytes_chainmap = shbytes_chainmap.parents # Access all dictionaries except first one
print(parent_shbytes_chainmap)
In this program, We are using shbytes_chainmap.parents to get all dictionaries except first one, from the ChainMap object. This will create a new ChainMap object parent_shbytes_chainmap without making change change to original object shbytes_chainmap.
Program Output
return new ChainMap containing all of the maps in current instance except the first one
# Original ChainMap object containing three dictionaries
ChainMap({1: 'a', 2: 'b'}, {3: 'c', 4: 'd'}, {5: 'e', 6: 'f'})
# ChainMap object with parents (all dictionaries except first)
ChainMap({3: 'c', 4: 'd'}, {5: 'e', 6: 'f'})
From the program output, new ChainMap object has two dictionaries ChainMap({3: 'c', 4: 'd'}, {5: 'e', 6: 'f'}) except first one.
keys(), values(), items() method in ChainMap
ChainMap class provides methods to access keys, values and items of all dictionaries or mappings (key-value pairs) from the ChainMap object
chain.keys()– Gives us theKeysViewof all the unique keys from the ChainMap object.KeysViewfrom this can be converted into any collection datatype like list, set, tuple etc. likelist(chain.keys())chain.values()– Gives us theValuesViewof all the unique values from the ChainMap object.ValuesViewfrom this can be converted into any collection datatype like list, set, tuple etc. likelist(chain.values())chain.items()– Gives us theItemsViewof all the unique items from the ChainMap object.ItemsViewfrom this can be converted into any collection datatype like list, set, tuple etc. likelist(chain.items())
#get all keys, values, items from ChainMap
print("get all keys, values, items from ChainMap")
from collections import ChainMap
dict_1 = {1: 'a', 2: 'b', 3: 'c'}
dict_2 = {3: 'c', 4: 'd', 5: 'e'}
dict_3 = {5: 'e', 6: 'f', 7: 'g'}
shbytes_chainmap = ChainMap(dict_1, dict_2, dict_3) # created ChainMap object of three dictionaries
print(shbytes_chainmap)
all_keys = shbytes_chainmap.keys() # Get KeysView from the ChainMap object
print("all keys view in ChainMap - ", all_keys)
print("all keys as list - ", list(all_keys)) # Get all unique keys as list from KeysView
print("all keys as set - ", set(all_keys)) # Get all unique keys as set from KeysView
all_values = shbytes_chainmap.values() # Get ValuesView from the ChainMap object
print("all values view in ChainMap - ", all_values)
print("all values as list - ", list(all_values)) # Get all unique values as list from ValuesView
print("all values as set - ", set(all_values)) # Get all unique values as set from ValuesView
all_items = shbytes_chainmap.items() # Get ItemsView from the ChainMap object
print("all items view in ChainMap - ", all_items)
print("all items as list - ", list(all_items)) # Get all unique items as list from ItemsView
print("all items as set - ", set(all_items)) # Get all unique items as set from ItemsView
Program Output for chain.keys(), chain.values(), chain.items()
get all keys, values, items from ChainMap
ChainMap({1: 'a', 2: 'b', 3: 'c'}, {3: 'c', 4: 'd', 5: 'e'}, {5: 'e', 6: 'f', 7: 'g'})
all keys view in ChainMap - KeysView(ChainMap({1: 'a', 2: 'b', 3: 'c'}, {3: 'c', 4: 'd', 5: 'e'}, {5: 'e', 6: 'f', 7: 'g'}))
all keys as list - [5, 6, 7, 3, 4, 1, 2]
all keys as set - {1, 2, 3, 4, 5, 6, 7}
all values view in ChainMap - ValuesView(ChainMap({1: 'a', 2: 'b', 3: 'c'}, {3: 'c', 4: 'd', 5: 'e'}, {5: 'e', 6: 'f', 7: 'g'}))
all values as list - ['e', 'f', 'g', 'c', 'd', 'a', 'b']
all values as set - {'g', 'a', 'e', 'b', 'c', 'd', 'f'}
all items view in ChainMap - ItemsView(ChainMap({1: 'a', 2: 'b', 3: 'c'}, {3: 'c', 4: 'd', 5: 'e'}, {5: 'e', 6: 'f', 7: 'g'}))
all items as list - [(5, 'e'), (6, 'f'), (7, 'g'), (3, 'c'), (4, 'd'), (1, 'a'), (2, 'b')]
all items as set - {(1, 'a'), (3, 'c'), (4, 'd'), (2, 'b'), (7, 'g'), (5, 'e'), (6, 'f')}
Collection from KeysView, ValuesView and ItemsView gives the unique keys, values and items respectively from all the dictionaries or mappings of the ChainMap object. List or Set collection for keys, values or items does not contain any duplicate element.
Get value at key – ChainMap
- We can use
chain.get(key)orchain[key]to get the value at given key. ChainMapsearches for keys in the dictionaries in the order they were provided. The first mapping in theChainMaphas the highest priority. If a key is found in the first dictionary, its value is returned immediately, and the search stops. If not, the search continues through the subsequent dictionaries.- If key does not found in any of the dictionaries of
ChainMapthenNoneis returned.
#get value at given key in ChainMap
print("get value at given key in ChainMap")
from collections import ChainMap
dict_1 = {1: 'a', 2: 'b', 3: 'c'}
dict_2 = {3: 'd', 4: 'e', 5: 'dict_2_5'}
dict_3 = {5: 'dict_3_5', 6: 'h', 7: 'i'}
shbytes_chainmap = ChainMap(dict_1, dict_2, dict_3)
print(shbytes_chainmap)
print("value at key 4 - ", shbytes_chainmap.get(4)) # get value using chain.get(key) method
print("value at key 5 - ", shbytes_chainmap[5]) # get value using chain[key]
print("value at key 12 - ", shbytes_chainmap.get(12)) # get value for key not present in ChainMap
In this program, we have create a ChainMap object shbytes_chainmap with three dictionaries.
dict_1anddict_2has common key3with different values.dict_2anddict_3has common key5with different values.shbytes_chainmap.get(4)will return the value at key4fromdict_2shbytes_chainmap[5]will return the value at key5fromdict_2. Based on the order of dictionariesdict_2is of higher order thandict_3. Key5fromdict_3will not be iterated.shbytes_chainmap.get(12)will return None. Key12does not exists in any of dictionaries in ChainMap object.
Program Output
get value at given key in ChainMap
ChainMap({1: 'a', 2: 'b', 3: 'c'}, {3: 'd', 4: 'e', 5: 'dict_2_5'}, {5: 'dict_3_5', 6: 'h', 7: 'i'})
value at key 4 - e
value at key 5 - dict_2_5
value at key 12 - None
Create ChainMap with default values
We can use chain.fromkeys(iterable, value) to create ChainMap object with default value.
print("fromkeys returns dictionary with the specified keys and value")
from collections import ChainMap
new_shbytes_chainmap = ChainMap.fromkeys([3, 'c2','l1','l2'], 'expert')
print(new_shbytes_chainmap)
In this program, we are using ChainMap.fromkeys([3, 'c2','l1','l2'], 'expert') to create ChainMap object with multiple elements each having default value.
Program Output
fromkeys returns dictionary with the specified keys and value
ChainMap({3: 'expert', 'c2': 'expert', 'l1': 'expert', 'l2': 'expert'})
This creates a ChainMap object with dictionary. Dictionary will have elements key from the iterable and with default value.
update() method
- Syntax –
chain.update({key:value,....,key:value}) update()method looks for the elements only in the first dictionary ofChainMap- If key found in the first dictionary, then it will update the value of that key
- else, it will add new key-value pair in the first dictionary
print("update() - inserts or updates the specified items in first dictionary")
from collections import ChainMap
dict_1 = {1: 'a', 2: 'b', 3: 'c'}
dict_2 = {3: 'd', 4: 'e', 5: 'dict_2_5'}
dict_3 = {5: 'dict_3_5', 6: 'h', 7: 'i'}
shbytes_chainmap = ChainMap(dict_1, dict_2, dict_3)
print(shbytes_chainmap)
shbytes_chainmap.update({3:"Learning"}) # Update key 3 in first dictionary
shbytes_chainmap.update({4:"Training"}) # Will add key 4 in the first dictionary
print(shbytes_chainmap)
In this program, we have created a ChainMap object ChainMap(dict_1, dict_2, dict_3). In this ChainMap object dict_1 is the first dictionary.
- Using
shbytes_chainmap.update({3:"Learning"})will update the value of key3in first dictionary, because key3already present indict_1. - Using
shbytes_chainmap.update({4:"Training"})will add new key-value pair in first dictionary, because key4does not exists indict_1.
Program Output
update() - inserts or updates the specified items in first dictionary
ChainMap({1: 'a', 2: 'b', 3: 'c'}, {3: 'd', 4: 'e', 5: 'dict_2_5'}, {5: 'dict_3_5', 6: 'h', 7: 'i'})
ChainMap({1: 'a', 2: 'b', 3: 'Learning', 4: 'Training'}, {3: 'd', 4: 'e', 5: 'dict_2_5'}, {5: 'dict_3_5', 6: 'h', 7: 'i'})
copy() method
chain.copy() creates a deep copy of the ChainMap object. After creating a copy, changes in the original ChainMap object will affect the new object.
#copy() - returns deep copy
print("copy() - returns deep copy")
from collections import ChainMap
training_dict = {1:"shbytes",2:"Online",3:"Training"}
courses_dict = {"c1":"Python","c2":"PowerBI","c3":"AWS"}
shbytes_chainmap = ChainMap(training_dict, courses_dict)
print(shbytes_chainmap)
copy_shbytes_chainmap = shbytes_chainmap.copy() # ChainMap copy
print(copy_shbytes_chainmap)
shbytes_chainmap["c3"] = "LLM" # Adding element in original object
print(copy_shbytes_chainmap)
- We have create a
ChainMapobject with two dictionaries, usingChainMap(training_dict, courses_dict) shbytes_chainmap.copy()will create a deep copy of the of the objectshbytes_chainmap["c3"] = "LLM", we are adding new element in original object which should not be reflected in copied object.
Program Output
copy() - returns deep copy
ChainMap({1: 'shbytes', 2: 'Online', 3: 'Training'}, {'c1': 'Python', 'c2': 'PowerBI', 'c3': 'AWS'})
ChainMap({1: 'shbytes', 2: 'Online', 3: 'Training'}, {'c1': 'Python', 'c2': 'PowerBI', 'c3': 'AWS'})
ChainMap({1: 'shbytes', 2: 'Online', 3: 'Training'}, {'c1': 'Python', 'c2': 'PowerBI', 'c3': 'AWS'})
# Same elements in copied object, even when original object was updated
Remove elements from ChainMap
chain.pop(key)removes the given key from the first dictionary ofChainMapobject. It returns the value of the key in dictionary.KeyErroris raised if key is not present in first dictionary ofChainMapobject.chain.popitem()will remove the last element from the first dictionary.KeyErroris raised if first dictionary is empty.del chain[key]can be used to delete the key from the first dictionary of ChainMap object.KeyErroris raised if key is not present in first dictionary ofChainMapobject.
# remove elements from first dictionary of ChainMap
print("remove elements from first dictionary of ChainMap")
from collections import ChainMap
courses_dict = {"c1":"Python","c2":"AWS","c3":"Azure", "c4":"LLM"}
training_dict = {1:"shbytes",2:"Online",3:"Training"}
shbytes_chainmap = ChainMap(courses_dict, training_dict)
print(shbytes_chainmap)
pop_value = shbytes_chainmap.pop("c2") # Take out key c2 from chainmap
print(shbytes_chainmap) # Print chainmap elements after removing key c2
print(pop_value) # Print return value for key c2
print("popitem - take out last item with given key from first dictioary in ChainMap")
popitem_element = shbytes_chainmap.popitem() # Takeout last item from the first dictionary
print(shbytes_chainmap) # Print chainmap elements after removing last item
print(popitem_element) # Print return item
del shbytes_chainmap["c3"] # Delete key c3 from first dictionary
print(shbytes_chainmap) # Print chainmap after deleting c3 key
Program Output
remove elements from first dictionary of ChainMap
# original ChainMap object
ChainMap({'c1': 'Python', 'c2': 'AWS', 'c3': 'Azure', 'c4': 'LLM'}, {1: 'shbytes', 2: 'Online', 3: 'Training'})
# Elements after pop key c2
ChainMap({'c1': 'Python', 'c3': 'Azure', 'c4': 'LLM'}, {1: 'shbytes', 2: 'Online', 3: 'Training'})
AWS # Return value of key c2
popitem - take out last item with given key from first dictioary in ChainMap
# Elements after popitem last element
ChainMap({'c1': 'Python', 'c3': 'Azure'}, {1: 'shbytes', 2: 'Online', 3: 'Training'})
('c4', 'LLM') # Return item
# Elements after delete key c3
ChainMap({'c1': 'Python'}, {1: 'shbytes', 2: 'Online', 3: 'Training'})
Summary
In this article, we learned about ChainMap collection in Python. Following topics were discussed:
- ChainMap
- ChainMap Properties
- ChainMap Object
- Empty ChainMap Object
- ChainMap Object with Dictionaries
- new_child() method – add child at front of ChainMap
- maps attribute – access ChainMap Mappings
- parents attribute – all ChainMap mappings except first
- keys(), values(), items() method in ChainMap
- Get value at key – ChainMap
- ChainMap with default values
- update() method
- copy() method
- Remove elements from ChainMap
Code – Github Repository
All code snippets and programs for this article and for Python tutorial, can be accessed from Github repository – Comments and Docstring in Python.