What is Nested Dictionary in Python?
One common data structure in Python is a nested dictionary, or a dictionary that can have other dictionaries as values for a given key. Beginners hate nested dictionaries because they require more time to work with and parse correctly, but it’s nothing you can’t manage with a bit of practice.
Today you’ll learn what is a nested dictionary, why to use nested dictionaries in Python, how to loop through a nested dictionary in Python, and much more. Regarding library imports, stick this to the top of your script or notebook:
import pprint
pp = pprint.PrettyPrinter(depth=4)
It will take care of formatting when printing nested dictionaries, so they’re a bit easier to read.
Refer to the following table of contents for everything this article covers:
Table of contents:
How to Create a Nested Dictionary in Python
There are many ways to create a nested dictionary, but you’ll primarily use two if you’re creating them from scratch in Python.
Using Regular Python Notation
The first way to create a nested Python dictionary is by leveraging regular Python notation. It means you don’t have to use any specific functions or libraries to create a dictionary. Simply assign it to a variable name, and format the entire thing as JSON.
Here’s an example - the following code snippet creates a nested dictionary of employees, where employee email is set for the dictionary key, and additional information as a dictionary value. As you can see, the dictionary value is also a dictionary:
employees = {
"bdoe@email.com": {
"first_name": "Bob",
"last_name": "Doe",
"address": {
"city": "New York",
"street": "1st Street",
"house_number": 1
}
},
"mmarkson@email.com": {
"first_name": "Mark",
"last_name": "Markson",
"address": {
"city": "San Diego",
"street": "2nd Street",
"house_number": 2
}
}
}
pp.pprint(employees)
Here’s what this nested dictionary looks like:
Overall, we have a dictionary with two keys (emails). Each of those keys has a dictionary for a value, and there’s even a third dictionary assigned to the address
key.
Dictionaries aren’t ordered, so that’s why you’re seeing the data not reflecting the ordering specified in the code. Don’t worry about that.
Using the zip() Function
An alternative way to create a nested dictionary in Python is by using the zip()
function. It’s used to iterate over two or more iterators at the same time.
To demonstrate, we’ll declare two lists:
employee_emails
- A list of emails that will represent the dictionary keysemployee_details
- A list of details for each employee, such as first name, last name, and address.
If you declare your data in this way, you can pass both to zip()
and wrap everything inside a call to dict()
. This will assign appropriate key-value pairs. Here’s the code:
employee_emails = ["bdoe@email.com", "mmarkson@email.com"]
employee_details = [
{
"first_name": "Bob",
"last_name": "Doe",
"address": {
"city": "New York",
"street": "1st Street",
"house_number": 1
}
},
{
"first_name": "Mark",
"last_name": "Markson",
"address": {
"city": "San Diego",
"street": "2nd Street",
"house_number": 2
}
}
]
employees = dict(zip(employee_emails, employee_details))
pp.pprint(employees)
The resulting data looks the same as what we had before:
In practice, there’s no reason to use this approach to declare nested dictionaries. It’s messy and takes longer to write. Just stick to the first one and you’ll be good to go.
Up next, let’s see how to access elements of a nested dictionary in Python.
How to Access Elements of a Nested Dictionary
You can access elements of a nested dictionary just like you would for a normal one, with one exception - you now need to add an additional set(s) of brackets.
Here are a couple of examples of what you can do:
- Access a single element
- Access a single element which is also a dictionary
- Concatenate multiple nested dictionary values
Or in code:
# Access element that contains a string
print(employees["bdoe@email.com"]["first_name"])
# Access element that contains a string
print(employees["bdoe@email.com"]["last_name"])
# Access element that contains a dictionary
print(employees["bdoe@email.com"]["address"])
# Combine multiple elements
print(f"{employees['bdoe@email.com']['first_name']} {employees['bdoe@email.com']['last_name']} from {employees['bdoe@email.com']['address']['city']}")
Here’s the output you should see:
Overall, you need as many brackets as there are levels in a nested dictionary if you want to get to the bottom. For example, to get the city for bdoe@email.com
, you would write employees["bdoe@email.com"]["address"]["email"]
. Easy!
How to Change Values in a Nested Dictionary
You now know how to access elements of a nested dictionary, but how can you change the values? It’s quite easy, and you can either change the values one by one or tackle multiple values at once.
Change a Single Value in a Nested Dictionary
You can change a single value in a nested dictionary by accessing it and assigning a new value.
The following example shows you how to change the complete address
for one employee, one value at a time:
# Change values one by one
employees["bdoe@email.com"]["address"]["city"] = "San Francisco"
employees["bdoe@email.com"]["address"]["street"] = "5th Street"
employees["bdoe@email.com"]["address"]["house_number"] = 5
pp.pprint(employees["bdoe@email.com"])
The updated employee now looks like this:
That’s great, but can you change the address
in one line? Sure you can, let’s explore how next.
Change Multiple Values in a Nested Dictionary
The address
property is a dictionary itself, which means you can change it completely in one line of Python code:
# Change multiple values at once
employees["mmarkson@email.com"]["address"] = {"city": "Los Angeles", "street": "15th Street", "house_number": 15}
pp.pprint(employees["mmarkson@email.com"])
Here’s what the updated employee looks like:
You now know how to access and change nested dictionary elements, so next we’ll go over adding new elements to a nested dictionary in Python.
How to Add Elements to a Nested Dictionary
Adding new elements to a nested dictionary in Python boils down to assigning a new key-value pair. It’s that simple!
The code snippet below declares two variables to hold the key and value for the new nested dictionary item, and then adds this pair by using the dictionary[key] = value
assignment operator:
new_employee_email = "jswift@email.com"
new_employee_details = {
"first_name": "Jane",
"last_name": "Swift",
"address": {
"city": "Boston",
"street": "10th Street",
"house_number": 10
}
}
# dictionary[key] = value
employees[new_employee_email] = new_employee_details
pp.pprint(employees)
Our updated nested dictionary now has 3 records:
That’s addition, so next let’s go over deletion.
How to Delete Elements from a Nested Dictionary
You can use Python’s del
keyword followed by the name of the dictionary and a key you want to delete. For example, run del d["name"]
to delete the key-value pair under the key of name
in the dictionary d
.
In our example, let’s use del
to delete the newly added employee:
del employees["jswift@email.com"]
pp.pprint(employees)
And we’re back to only two records now:
Up next, let’s go over merging two or more dictionaries.
How to Merge Two Nested Dictionaries
Dictionary merging just means you want to take two or more dictionaries and combine them into a single one. It helps if the structure of dictionaries is identical, but it’s not required, since this is Python.
To demonstrate, let’s declare a new nested dictionary of employees:
new_employees = {
"jswift@email.com": {
"first_name": "Jane",
"last_name": "Swift",
"address": {
"city": "Boston",
"street": "25th Street",
"house_number": 25
}
},
"pjohnson@email.com": {
"first_name": "Patrick",
"last_name": "Johnson",
"address": {
"city": "Miami",
"street": "50th Street",
"house_number": 50
}
}
}
pp.pprint(new_employees)
Here’s what it looks like:
The idea is to add this dictionary to the one we already have, and there are two ways to do so.
Merge Two Dictionaries with the update() Function
The update()
function updates one dictionary with the contents of another. The updating happens inplace, which means you don’t have to reassign the variable.
Here’s an example:
employees.update(new_employees)
pp.pprint(employees)
Our updated nested dictionary now has four records:
This function is easy to work with, but the downside is that you can only add one dictionary at a time. The next approach is a bit more flexible.
Merge Two Dictionaries with **kwargs
The **kwargs
approach might look strange to newcomers, but it essentially just unpacks a dictionary. By doing so, you can unpack as many dictionaries as you want into a single new dictionary.
Here’s an example:
emps_merged = {**employees, **new_employees}
pp.pprint(emps_merged)
The merged nested dictionary is identical to the one we had earlier:
Ultimately, it’s up to you to decide on the best merging approach. We recommend **kwargs
since you can merge dozens of dictionaries in a single line of Python code.
How to Iterate Through a Nested Dictionary
There’s no one-size-fits-all solution when it comes to iterating through a nested dictionary in Python. A structure of a dictionary item will vary, which means you’ll have to customize the code every time.
To show you how, we’ll go over two examples, one simpler and the other a bit heavier on the code side.
The first example iterates over all dictionary items and prints the key, and then also iterates through the corresponding value and prints it. Here’s the code:
# Keys and values
for emp_email, emp_info in employees.items():
print(f"EMAIL: {emp_email}")
# For each key that belongs to a dictionary at the given email
for key in emp_info:
# Print the corresponding key and value
print(f"{key} = {emp_info[key]}")
print()
This is what you should see:
This approach might work if you don’t have an additional level of nesting, similar to what we have with address
. It’s much more challenging to address this, but let’s give it a try next.
More Advanced Iteration Example
The idea now is to step into the address
dictionary and print all of the elements it contains.
To make the code a bit more robust, we’ll check if the item is a dictionary, and if so, iterate through its items. If the tem is not a dictionary, we’ll simply print it:
# Keys and values
for emp_email, emp_info in employees.items():
print(f"EMAIL: {emp_email}")
# For every key in the inner dictionary
for key in emp_info:
# Check if a type is a dictionary
if type(emp_info[key]) is dict:
print(f"{key}:")
# Print nested items
for item in emp_info[key]:
print(f"\t{item} = {emp_info[key][item]}")
# Not a dictionary, print the value
else:
print(f"{key} = {emp_info[key]}")
print()
Here’s what you should see on the screen:
Overall, we’ve managed to parse our nested dictionary structure, but again, this won’t work on all nested dictionaries. You’ll have to customize the code snippet to accommodate your use case, which can be tricky and time-consuming.
How to Flatten a Nested Dictionary
Flattening a nested dictionary means you want to get a dictionary that doesn’t contain any dictionaries or lists inside.
This is a very common data preprocessing technique when parsing nested JSON documents to a Pandas DataFrame. If that’s what you’re dealing with, you know the structure of the input data will be quite different.
Most of the time, you’ll have a list of dictionaries. We’ll declare one such list below, and add the email
property inside each employee object instead of using it as a dictionary key:
employees = [
{
"first_name": "Bob",
"last_name": "Doe",
"email": "bdoe@email.com",
"address": {
"city": "New York",
"street": "1st Street",
"house_number": 1
}
},
{
"first_name": "Mark",
"last_name": "Markson",
"email": "mmarkson@email.com",
"address": {
"city": "San Diego",
"street": "2nd Street",
"house_number": 2
}
}
]
Once you have the data in this format, it’s time to flatten it. The following recursive function flattens one record, or one dictionary element inside a list. For any nested dictionary, it finds it will flatten it in a way that the key renames to the full path.
The flatten_dict()
function has to be applied on each record in a list of dictionaries, meaning you can use either a Python loop or a list comprehension.
Here’s an example:
def flatten_dict(d: dict) -> dict:
out = {}
def flatten(x, name: str = ''):
if type(x) is dict:
for a in x:
flatten(x[a], name + a + '_')
elif type(x) is list:
i = 0
for a in x:
flatten(a, name + str(i) + '_')
i += 1
else:
out[name[:-1]] = x
flatten(d)
return out
# Apply the function to each row
employees_flat = [flatten_dict(emp) for emp in employees]
pp.pprint(employees_flat)
We now have a completely flat structure:
Note how address
was appended before its inner key-value pairs, so we still get the idea of where it belonged originally.
Now when you have a flat list of dictionaries, you can convert it into a Pandas DataFrame.
Nested Dictionary Python to Pandas DataFrame
If you want to convert a nested dictionary to a Pandas DataFrame, you’ll have to flatten it first. Otherwise, you’ll get weird indexing and possibly a dictionary for the value of a single cell.
Let’s demonstrate a bad practice first, so you can get the idea of why flatten the data. Below we have an identical dictionary of employees to the one we used throughout the article. We’re then using it in a call to pd.DataFrame()
:
import pandas as pd
employees = {
"bdoe@email.com": {
"first_name": "Bob",
"last_name": "Doe",
"address": {
"city": "New York",
"street": "1st Street",
"house_number": 1
}
},
"mmarkson@email.com": {
"first_name": "Mark",
"last_name": "Markson",
"address": {
"city": "San Diego",
"street": "2nd Street",
"house_number": 2
}
}
}
pd.DataFrame(employees)
Here’s what the resulting DataFrame looks like:
Terrible and not usable. You need to pass a list of flattened dictionaries to pd.DataFrame()
to get back the data in the appropriate format.
You already know how to flatten a nested dictionary, so this should feel like a walk in the park:
employees = [
{
"first_name": "Bob",
"last_name": "Doe",
"email": "bdoe@email.com",
"address": {
"city": "New York",
"street": "1st Street",
"house_number": 1
}
},
{
"first_name": "Mark",
"last_name": "Markson",
"email": "mmarkson@email.com",
"address": {
"city": "San Diego",
"street": "2nd Street",
"house_number": 2
}
}
]
# Flatten the records first
employees_flat = [flatten_dict(emp) for emp in employees]
pd.DataFrame(employees_flat)
The DataFrame is now much easier to understand and analyze:
And finally, let’s cover nested dictionary to JSON conversion.
Nested Dictionary Python to JSON File
JSON and Python dictionaries go hand in hand, meaning you can easily go from a JSON file to a Python dictionary and vice-versa.
We’ll show you how to go from a nested Python dictionary to a JSON file. You’ll need to import the json
module and pass in your dictionary to json.dumps()
. The optional indent
parameter controls the indentation of nested structures inside a dictionary.
Here’s the code:
import json
employees = {
"bdoe@email.com": {
"first_name": "Bob",
"last_name": "Doe",
"address": {
"city": "New York",
"street": "1st Street",
"house_number": 1
}
},
"mmarkson@email.com": {
"first_name": "Mark",
"last_name": "Markson",
"address": {
"city": "San Diego",
"street": "2nd Street",
"house_number": 2
}
}
}
json_object = json.dumps(employees, indent=4)
print(json_object)
And this is what your JSON object should look like:
You can now use Python’s context manager syntax to write the JSON object to a file. This code snippet writes it to a file named employees.json
:
with open("employees.json", "w") as f:
json.dump(employees, f)
You can open the JSON file in any text editor or even in JupyterLab. You’ll see something similar to this:
And that’s how you can work with nested dictionaries in Python. Let’s make a short recap next.
Summing up Nested Dictionary Python
There’s a lot that goes into working with nested dictionaries in Python. You can access individual values, change them, add new rows, delete old ones, merge multiple dictionaries, iterate over them, and even convert the entire thing to a Pandas DataFrame or JSON file.
Unfortunately, there’s no one-size-fits-all solution when it comes to nested dictionaries. The structure of one will vary from project to project, which means you’ll have to customize the code to match your scenario. That’s especially true when it comes to iterating through nested dictionaries.
This article should give you a good starting point and will cover 95% of scenarios, and you can always explore further on your own.
What’s your favorite thing about nested dictionaries? Are they giving you a lot of headaches in daily data science tasks? Let me know in the comment section below.