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)
collections
is a module in Python.ChainMap
class is part ofcollections
module. We need to importcollections
module to useChainMap
class in our program.ChainMap()
is theChainMap
class constructor*dictionaries
is the group of dictionaries to be as an argument. We can multiple dictionaries as the same time.chainMap_object
is the object returned
ChainMap
Properties
There are many properties of Chainmap
collection.
- Order of dictionaries in
ChainMap
object is very important. - Search Order –
ChainMap
searches for keys in the dictionaries in the order they were provided. The first mapping in theChainMap
has 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 –
ChainMap
provides a dynamic view of the dictionaries. If any of the original dictionaries are updated or changed, those changes will be reflected in theChainMap
object. - Modifications – Assigning a value to a key in a
ChainMap
will 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
ChainMap
can be added using thenew_child()
method. This creates a newChainMap
with the new dictionary as the first element, leaving the originalChainMap
unchanged. - Accessing Dictionaries –
maps
attribute of aChainMap
returns a list of the dictionaries it contains. We can access, modify, or reorder these dictionaries if needed. - Key Deletion – Deleting a key from a
ChainMap
will only remove the key from the first dictionary in which it is found. If the key is not found in the first dictionary, aKeyError
is raised. - Read-only View –
ChainMap
provides a unified view of multiple dictionaries, it does not merge the dictionaries. Each dictionary remains distinct, and no data is copied. This makesChainMap
memory-efficient, especially when dealing with large datasets or numerous dictionaries. ChainMap
is 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
ChainMap
yields keys from the first dictionary that contains them, preserving the order of the dictionaries. Duplicate keys in later dictionaries are ignored during iteration. - Compatibility –
ChainMap
works 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.
ChainMap
Object
Empty 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
ChainMap
object is created, with the new dictionary as the first element. new_child()
method does not make any change in originalChainMap
object.
ChainMap
Add empty child at front of # 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.
ChainMap
Add dictionary with elements as new child at front of #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
parents
attribute to get all dictionaries or mappings (key-value pair) except first. - A new
ChainMap
object is created, which will not have first dictionary. parents
attribute does not make any change in originalChainMap
object.
#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 theKeysView
of all the unique keys from the ChainMap object.KeysView
from this can be converted into any collection datatype like list, set, tuple etc. likelist(chain.keys())
chain.values()
– Gives us theValuesView
of all the unique values from the ChainMap object.ValuesView
from this can be converted into any collection datatype like list, set, tuple etc. likelist(chain.values())
chain.items()
– Gives us theItemsView
of all the unique items from the ChainMap object.ItemsView
from 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. ChainMap
searches for keys in the dictionaries in the order they were provided. The first mapping in theChainMap
has 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
ChainMap
thenNone
is 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_1
anddict_2
has common key3
with different values.dict_2
anddict_3
has common key5
with different values.shbytes_chainmap.get(4)
will return the value at key4
fromdict_2
shbytes_chainmap[5]
will return the value at key5
fromdict_2
. Based on the order of dictionariesdict_2
is of higher order thandict_3
. Key5
fromdict_3
will not be iterated.shbytes_chainmap.get(12)
will return None. Key12
does 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
ChainMap
with default values
Create 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 key3
in first dictionary, because key3
already present indict_1
. - Using
shbytes_chainmap.update({4:"Training"})
will add new key-value pair in first dictionary, because key4
does 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
ChainMap
object 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
ChainMap
Remove elements from chain.pop(key)
removes the given key from the first dictionary ofChainMap
object. It returns the value of the key in dictionary.KeyError
is raised if key is not present in first dictionary ofChainMap
object.chain.popitem()
will remove the last element from the first dictionary.KeyError
is raised if first dictionary is empty.del chain[key]
can be used to delete the key from the first dictionary of ChainMap object.KeyError
is raised if key is not present in first dictionary ofChainMap
object.
# 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.