python
25 lines · 6 steps
How a recursive deep merge works in Python
Combine nested dictionaries by recursing into shared keys while copying values so the inputs stay untouched.
Explained by
highlit
1from copy import deepcopy
2from typing import Any, Mapping
3
4
5def deep_merge(base: Mapping[str, Any], override: Mapping[str, Any]) -> dict:
6 result = deepcopy(dict(base))
7
8 for key, override_value in override.items():
9 base_value = result.get(key)
10
11 if isinstance(base_value, Mapping) and isinstance(override_value, Mapping):
12 result[key] = deep_merge(base_value, override_value)
13 elif isinstance(base_value, list) and isinstance(override_value, list):
14 result[key] = base_value + deepcopy(override_value)
15 else:
16 result[key] = deepcopy(override_value)
17
18 return result
19
20
21def merge_configs(*configs: Mapping[str, Any]) -> dict:
22 merged: dict = {}
23 for config in configs:
24 merged = deep_merge(merged, config)
25 return merged
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Recursing on matching Mapping keys lets you merge arbitrarily nested structures without hand-writing each level.
- 2Deep-copying values keeps the original inputs immutable, avoiding shared-reference bugs across merges.
- 3Folding a merge over a sequence turns a two-argument combiner into a variadic one with a clear precedence order.
Related explainers
python
from difflib import SequenceMatcher from bisect import bisect_left, bisect_right
Building a fuzzy autocomplete matcher
fuzzy-matching
binary-search
ranking
Intermediate
9 steps
javascript
function deepFreeze(obj) { const propNames = Reflect.ownKeys(obj); for (const name of propNames) {
Recursively freezing a nested object
recursion
immutability
object-freezing
Intermediate
6 steps
python
import secrets from datetime import datetime, timedelta, timezone from fastapi import APIRouter, Cookie, Depends, HTTPException, Response, status
Cookie session auth in FastAPI
session-authentication
cookies
dependency-injection
Intermediate
8 steps
ruby
class QueryProxy ALLOWED = %i[where limit offset order includes distinct].freeze def initialize(relation, operations = [])
Building a lazy query proxy in Ruby
metaprogramming
method_missing
lazy-evaluation
Advanced
7 steps
php
final class Route { private string $regex; private array $paramNames = [];
Compiling route patterns into regex in PHP
routing
regex
parsing
Intermediate
8 steps
python
from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer from jose import JWTError, jwt from sqlalchemy.orm import Session
Chaining auth dependencies in FastAPI
dependency-injection
jwt-authentication
authorization
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/how-a-recursive-deep-merge-works-in-python-explained-python-d49b/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.