A nested dictionary is a dictionary whose values are themselves dictionaries. While a flat dictionary maps keys to simple values like numbers or strings, a nested dictionary organizes data into a hierarchy. The outer dictionary's keys are categories, sections, or parent identifiers, and each inner dictionary holds the details for that category. If you have ever worked with JSON data from a web API, you have already used nested dictionaries: JSON objects map directly to Python dictionaries, and a JSON document with nested objects becomes a nested dictionary structure.
The skills from earlier articles in this section apply directly to nested dictionaries. Accessing an inner value uses the same square-bracket syntax, just chained across multiple levels. The get method for safe access works at every level. And the caution from the article on copying Python lists about shallow copies applies even more forcefully to nested dictionaries: a shallow copy of a nested dictionary shares the inner dictionaries with the original, and modifying an inner dictionary through the copy changes it for the original as well.
Creating nested dictionaries
The most direct way to create a nested dictionary is to write it as a literal with inner dictionaries indented for readability. Each level of indentation corresponds to a level of nesting, and the structure mirrors the JSON format that nested dictionaries often represent.
users = {
"alice": {"role": "admin", "active": True},
"bob": {"role": "editor", "active": False},
}This creates a dictionary where the key "alice" maps to an inner dictionary with two keys, and the key "bob" maps to a different inner dictionary with its own set of values. Accessing the role of a specific user requires chaining the outer and inner keys: users["alice"]["role"] returns "admin".
For programmatic construction, where you do not know the keys ahead of time, you build nested dictionaries incrementally. The most important rule is to create each inner dictionary as a new, independent object. A common beginner mistake is to use the same dictionary literal or the same dict constructor call for multiple outer keys, which results in all those keys sharing a single inner dictionary. Changing one then silently changes all the others.
config = {}
for section in ["database", "cache", "logging"]:
config[section] = {}Each iteration creates a fresh empty dictionary and assigns it to a different outer key. The three inner dictionaries are independent, and modifying one section's configuration will not affect the others. This pattern, creating inner dictionaries inside a loop, is the safe way to build nested structures dynamically.
Safe access with get
Deeply nested access with square brackets is fragile: if any intermediate key is missing, Python raises a KeyError and the entire chain fails. For JSON data from external sources, where you cannot guarantee that every optional field is present, chained calls to the get method provide a safe alternative.
The pattern is to call get on each dictionary in the chain, providing an empty dictionary as the default for every level except the last. If a key is missing, get returns the empty default, and the next get call in the chain safely returns its own default instead of raising an error. The final get provides the actual fallback value for the data you are trying to retrieve.
This pattern is verbose when written out fully, but it is the standard way to handle optional nested keys without try/except blocks. For deeply nested structures with many optional levels, helper libraries and the glom package exist, but for most beginner and intermediate use cases, chained get calls or a single try/except at the outer level are sufficient and keep the code readable.
Nested dictionaries from comprehensions
Dictionary comprehensions can create nested structures directly. The value expression in a comprehension can itself be another dictionary comprehension, building the inner dictionary for each outer key in a single statement. This is the most expressive way to create a nested dictionary when the inner structure follows a pattern.
teams = ["red", "blue"]
players = ["ana", "sam"]
rosters = {team: {p: 0 for p in players} for team in teams}The comprehension reads from the inside out: the inner comprehension builds a fresh dictionary mapping each player to a starting score of 0, and the outer comprehension maps each team name to its own copy of that inner dictionary. The result, rosters, gives every team an independent scoreboard, so updating rosters["red"]["ana"] never touches rosters["blue"]. This pattern mirrors the nested list comprehensions covered in list comprehensions in Python, applied to dictionaries instead of lists.
Defaultdict for auto-creating inner dictionaries
The defaultdict class from the collections module simplifies nested dictionary construction by automatically creating inner dictionaries when a new key is accessed. When you create a defaultdict with dict as the default factory, accessing a missing key creates an empty dictionary at that key and returns it, ready for further assignment.
from collections import defaultdict
grades = defaultdict(dict)
grades["Alice"]["math"] = 95The first line accesses grades["Alice"], which does not yet exist. Instead of raising a KeyError, defaultdict creates an empty dictionary at that key and returns it. The second line then assigns 95 to the key "math" inside that newly created inner dictionary. This pattern eliminates the need to check whether an inner dictionary exists before assigning to it, and it is the standard approach for building nested dictionaries when the structure grows organically as data arrives.
For further exploration of how Python handles dynamic data structures that grow during program execution, the article on iterating through Python collections covers patterns for processing nested and hierarchical data efficiently.
Rune AI
Key Insights
- A nested dictionary is a dictionary whose values are themselves dictionaries.
- Access nested values by chaining square brackets: dict[key1][key2].
- Use get() with a default at each level to safely access deeply nested keys.
- Create each inner dictionary independently to avoid shared-reference bugs.
- The defaultdict with dict as the factory auto-creates missing inner dictionaries.
Frequently Asked Questions
How do I access a value deep inside a nested dictionary?
What is the cleanest way to create a nested dictionary of arbitrary depth?
Why does modifying a nested dictionary sometimes change another one?
Conclusion
Nested dictionaries model hierarchical data naturally in Python. They are the native format for parsed JSON, configuration with sections, and any data that organizes into categories and subcategories. Understanding how to access, create, and safely copy nested dicts prevents the shared-reference bugs that are among the most frustrating for beginners.
More in this topic
Nested Lists in Python
Learn how to create, access, and modify nested lists in Python. Build grids and matrices, and understand how shallow copies affect multi-dimensional data.
List Comprehensions in Python
Master Python list comprehensions to create, filter, and transform lists in a single line. Learn the syntax, common patterns, and when to use a regular loop instead.
Copy Python Lists
Learn how to copy Python lists using slicing, the copy method, the list constructor, and the copy module. Understand shallow vs deep copies.