The Python collections module provides Python’s implementations of chain maps with the ChainMaps class. This allows you to implement multiple dictionaries in the same context. This means that you can maintain multiple dictionaries, but access them as though they were a single dictionary. In this tutorial, you’ll learn how to use the ChainMap class from the Python collections module to manage multiple contexts.
By the end of this tutorial, you’ll have learned the following:
- How to use the ChainMap class from the Python collections module
- What the benefits of using a chain map are
- What the differences between ChainMaps and dictionaries are
- How to manage lookup and update priorities in Python ChainMap
Table of Contents
Understanding the Python collections ChainMap
A ChainMap is used to group multiple dictionaries to a single view that provides dictionary-like behavior, as though the dictionaries were a single dictionary. What’s more, is that the ChainMap also allows you to define priority both in terms of looking up values and updating values.
A ChainMap technically only points to different dictionaries, meaning that they are quite efficient. Similarly, the dictionaries allow you to perform a key lookup without needing to know which dictionary to reference. This allows you to use the same interface that you would with a dictionary, though the chained dictionaries can contain duplicate keys (which are treated with different priorities).
This may all seem quite abstract at the moment, so let’s dive into how to create a ChainMap with Python.
Creating a ChainMap in Python with the collections Module
In order to create a ChainMap in Python, you can import the class directly from the collections module. The class was added in Python version 3.3 and has had a number of different improvements in the following versions. Let’s see how we can chain and map together multiple dictionaries into a single ChainMap:
# Creating Your First ChainMap
from collections import ChainMap
netflix = {'Harry Potter': '2022-01-01', 'Lord of the Rings': '2021-12-23'}
hulu = {'The Office': '2023-03-01', 'Harry Potter': '2022-03-01'}
amazon_prime = {'Lord of the Rings': '2020-01-01', '30 Rock': '2023-01-01'}
all_services = ChainMap(netflix, hulu, amazon_prime)
print(all_services)
# Returns:
# ChainMap({'Harry Potter': '2022-01-01', 'Lord of the Rings': '2021-12-23'}, {'The Office': '2023-03-01', 'Harry Potter': '2022-03-01'}, {'Lord of the Rings': '2020-01-01', '30 Rock': '2023-01-01'})
In the example above, we created our first ChainMap. In order to do this, we followed the steps below:
- We imported the ChainMap class from the collections module
- We then created three dictionaries, each representing a streaming service and the movies or TV shows that it offers (as well as the date they were added)
- We then created a ChainMap by passing all three services into the ChainMap instantiator
- Finally, we printed the ChainMap to see what it looks like
We can see that when we printed the ChainMap, it showed all three dictionaries inside of our ChainMap object. This is where things get interesting – if we try to access an item in the ChainMap, we can access the ChainMap itself!
Let’s see how we can look for an item in the ChainMap:
# Accessing an Item in a ChainMap
from collections import ChainMap
netflix = {'Harry Potter': '2022-01-01', 'Lord of the Rings': '2021-12-23'}
hulu = {'The Office': '2023-03-01', 'Harry Potter': '2022-03-01'}
amazon_prime = {'Lord of the Rings': '2020-01-01', '30 Rock': '2023-01-01'}
all_services = ChainMap(netflix, hulu, amazon_prime)
print(all_services.get('Harry Potter'))
# Returns:
# 2022-01-01
We can see that when we use the .get()
method to find an item in the ChainMap, it returned the value. Remember, this is the standard, safe way of accessing an item in a dictionary. What’s interesting here is that the method returned only a single value, even though the item exists in two dictionaries.
ChainMaps will prioritize getting dictionary values based on the order in which the dictionaries are added to the ChainMap. We can see how this works in that netflix
is added before hulu
. Because of this, the value for 'Harry Potter'
is taken from the netflix
dictionary.
Similar to regular Python dictionaries, we have two ways of accessing values. Let’s take a look at them:
- The
.get()
method, which returnsNone
if a key doesn’t exist in any of the dictionaries, or a default value if its passed in. - The
[]
indexing method, which will cause aKeyError
if a key doesn’t exist.
Let’s now take a look at some of the differences between a ChainMap and normal Python dictionaries.
Understanding the Benefits of a ChainMap over a Dictionary
At this point, you may be wondering what the benefits of a ChainMap are over a regular Python dictionary. Let’s take a look at three key benefits that a ChainMap provides over a regular Python dictionary:
- Prioritizing lookup values – A ChainMap will look up values in the priorities of each of the dictionaries that are passed in. This can be helpful if you’re building command-line applications, where you need to manage multiple lookups in different priorities.
- Providing a single reference point for multiple lookups – If you need to search through multiple dictionaries at once, ChainMaps can be very helpful. Rather than needing to handle complex if-else statements, ChainMaps provide a single lookup point.
- Improved performance when managing multiple lookups – if your application depends on multiple lookups, ChainMaps can provide performance improvements. Depending on the complexity of the applications, this can be significant.
Now that you’ve developed a strong understanding of ChainMaps can be beneficial, let’s dive into understanding the lookup and update priorities in ChainMaps.
Understanding Lookup and Update Priorities in Python ChainMap
In this section, you’ll learn about the lookup and update priorities used in the Python ChainMap class. We’ve already taken a brief look at how lookup priorities work. In a nutshell, items are looked up in the order in which they are added when the ChainMap is created. Let’s take a look at our earlier example again:
# Accessing an Item in a ChainMap
from collections import ChainMap
netflix = {'Harry Potter': '2022-01-01', 'Lord of the Rings': '2021-12-23'}
hulu = {'The Office': '2023-03-01', 'Harry Potter': '2022-03-01'}
amazon_prime = {'Lord of the Rings': '2020-01-01', '30 Rock': '2023-01-01'}
all_services = ChainMap(netflix, hulu, amazon_prime)
print(all_services.get('Harry Potter'))
# Returns:
# 2022-01-01
When we look up 'Harry Potter'
, the ChainMap returns the instance from netflix
. This is because when we created our ChainMap, netflix
was added first. Because of this, even though hulu
also contains the key, this value isn’t returned. This is because ChainMaps prioritize based on when the items were inserted.
In terms of updating items, things get a little bit confusing. When we update an item, one of two things can happen:
- If the item exists in the first dictionary in the ChainMap, the value for that key is updated.
- If the item does not exist in the first dictionary in the ChainMap, the key-value pair is created in that dictionary – even if the key exists in another dictionary.
Let’s take a look at what this looks like. We’ll try to update the key of 'The Office'
, which exists in the second dictionary:
# Updating a Key in a ChainMap
from collections import ChainMap
netflix = {'Harry Potter': '2022-01-01', 'Lord of the Rings': '2021-12-23'}
hulu = {'The Office': '2023-03-01', 'Harry Potter': '2022-03-01'}
amazon_prime = {'Lord of the Rings': '2020-01-01', '30 Rock': '2023-01-01'}
all_services = ChainMap(netflix, hulu, amazon_prime)
all_services['The Office'] = '2022-02-02'
print(all_services)
# Returns:
# ChainMap({'Harry Potter': '2022-01-01', 'Lord of the Rings': '2021-12-23', 'The Office': '2022-02-02'}, {'The Office': '2023-03-01', 'Harry Potter': '2022-03-01'}, {'Lord of the Rings': '2020-01-01', '30 Rock': '2023-01-01'})
We can see that the key for the office was added to the first dictionary, despite already existing in the second one. If we wanted to update the key in the second dictionary, we would need to update the dictionary itself. Because ChainMaps hold on the references to the dictionaries, updating the dictionary outside the ChainMap would update it in the ChainMap, too.
Conclusion
In this tutorial, you learned how to use the ChainMap class from the Python collections module. The class allows you to easily map and chain together multiple dictionaries. In a ChainMap, you can navigate multiple dictionaries, as if they were the same one. This allows you to easily manage different contexts, without complexity.
You first learned how to create and use ChainMaps, by using the class from the collections module. From there, you learned what the benefits of a ChainMap are, as compared to regular Python dictionaries. Finally, you learned how to use ChainMaps to identify lookup and update priorities.
Additional Resources
To learn more about related topics, check out the tutorials below: