Update value of a nested dictionary of varying depth
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
Python's built-in dict.update() only merges at the top level — nested dictionaries are replaced, not merged. To recursively update a nested dictionary of arbitrary depth, you need a custom function that walks both dictionaries and merges at every level. This is essential when merging configuration files, API responses, or any hierarchical data where you want to preserve existing nested values while updating specific keys.
The Problem with dict.update()
update() replaced the entire "database" dictionary with the override, losing host, port, and user.
Recursive Deep Merge
Only the password key was updated. All other nested values were preserved.
Non-Mutating Version
The function above modifies base in place. To preserve the original:
Setting a Value at an Arbitrary Path
Update a specific key path like ["database", "credentials", "password"]:
setdefault creates intermediate dictionaries if they do not exist.
Getting a Value at an Arbitrary Path
Deleting a Nested Key
Using Libraries
For production code, use established libraries:
Merging Multiple Dictionaries
Common Pitfalls
- Using
dict.update()for nested merging:update()replaces nested dictionaries entirely instead of merging them. Always use a recursive function for nested data. - Modifying the original dictionary: The in-place
deep_updatefunction mutatesbase. If you need to preserve the original, usecopy.deepcopy()first or use the non-mutatingdeep_mergeversion. - Infinite recursion with circular references: If a dictionary contains references to itself (e.g.,
d["self"] = d), recursive merge loops forever. Add a depth limit or a visited-set guard for untrusted input. - Non-dict values at merge points: If
base["key"]is a string butoverride["key"]is a dict (or vice versa), the recursive checkisinstance(base[key], dict) and isinstance(value, dict)correctly replaces instead of merging. Ensure this behavior matches your expectations. - List merging: The recursive function above replaces lists entirely. If you need to merge lists (append, deduplicate, or zip), add explicit list handling:
if isinstance(base[key], list) and isinstance(value, list): base[key].extend(value).
Summary
dict.update()only merges the top level — nested dicts are replaced, not merged- Use a recursive
deep_updatefunction to merge at every nesting level - Use
copy.deepcopy()for a non-mutating merge that preserves the original - Use
setdefaultin a loop to set values at arbitrary key paths - For production code, consider libraries like
deepmergeorpython-box - Handle edge cases: circular references, type mismatches at merge points, and list values
Related reading
- Usage of protocols as array types and function parameters in Swift
- Usage of protocols as array types and function parameters in Swift
- Use cases for the 'setdefault' dict method
- Use celery priority queue with broadcast tasks
- Updating the feature names into scikit TFIdfVectorizer
- Upgrade Python in a virtual environment
- Use Dijkstra's to find a Minimum Spanning Tree?
- Use WEKA API to perform LSA on train and test set

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.