Nested Dictionary Python - A Complete Guide to Python Nested Dictionaries

Nested Dictionary Python - A Complete Guide to Python Nested Dictionaries

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.

New to Python? Learn basic Dictionaries First.

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:


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:

Image 1 - Nested dictionary of employees (image by author)

Image 1 - Nested dictionary of employees (image by author)

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 keys
  • employee_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:

Image 2 - Nested dictionary of employees (2) (image by author)

Image 2 - Nested dictionary of employees (2) (image by author)

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:

Image 3 - Accessing elements of a nested Python dictionary (image by author)

Image 3 - Accessing elements of a nested Python dictionary (image by author)

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:

Image 4 - Changing a single value in a nested dictionary (image by author)

Image 4 - Changing a single value in a nested dictionary (image by author)

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:

Image 5 - Changing multiple values in a nested dictionary (image by author)

Image 5 - Changing multiple values in a nested dictionary (image by author)

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:

Image 6 - Adding elements to a nested dictionary in Python (image by author)

Image 6 - Adding elements to a nested dictionary in Python (image by author)

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:

Image 7 - Deleting elements from a nested dictionary (image by author)

Image 7 - Deleting elements from a nested dictionary (image by author)

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:

Image 8 - Two new employees (image by author)

Image 8 - Two new employees (image by author)

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:

Image 9 - Merging nested dictionaries (image by author)

Image 9 - Merging nested dictionaries (image by author)

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:

Image 10 - Merging nested dictionaries (2) (image by author)

Image 10 - Merging nested dictionaries (2) (image by author)

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:

Image 11 - Iterating through a nested dictionary (image by author)

Image 11 - Iterating through a nested dictionary (image by author)

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:

Image 12 - Iterating through a nested dictionary (2) (image by author)

Image 12 - Iterating through a nested dictionary (2) (image by author)

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:

Image 13 - Flattening a nested dictionary (image by author)

Image 13 - Flattening a nested dictionary (image by author)

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:

Image 14 - Nested dictionary to a Pandas DataFrame (image by author)

Image 14 - Nested dictionary to a Pandas DataFrame (image by author)

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:

Image 15 - Nested dictionary to a Pandas DataFrame (2) (image by author)

Image 15 - Nested dictionary to a Pandas DataFrame (2) (image by author)

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:

Image 16 - Nested dictionary to a JSON object (image by author)

Image 16 - Nested dictionary to a JSON object (image by author)

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:

Image 17 - Nested dictionary to a JSON file (image by author)

Image 17 - Nested dictionary to a JSON file (image by author)

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.