Merging dictionaries means combining two (or more) key–value sources into one mapping you can read or pass on. You might need a brand-new dict, an in-place update, or a layered lookup without copying everything up front. This guide walks through the operators and stdlib tools people use in practice, when duplicate keys overwrite, how that differs across Python versions, and what to avoid.
If you need a refresher on how dicts work first, see the Python dictionary tutorial. To extend an existing dict in place after merging, see Python dict extend; for nested structures, see nested dictionary in Python.
Tested on: Python 3.13.3; kernel 6.14.0-37-generic.
Merge dictionaries using the | operator
Python 3.9 added the merge operator | for dictionaries. The expression a | b builds a new dict containing all keys from a and b. Where the same key appears in both, the value from the right-hand dict (b) wins. Neither operand is modified.
d1 = {'fruit': 'Apple', 'calories': 100}
d2 = {'vegetable': 'Tomato', 'calories': 50}
result = d1 | d2
print('d1 unchanged:', d1)
print('merged:', result)Running the snippet prints d1 with calories still 100, while result has calories 50 (from d2) plus vegetable. On Python 3.8 or earlier, this syntax is not available; use {**d1, **d2} or update on a copy instead.
Merge dictionaries in-place using |=
The augmented assignment |= merges the right dict into the left dict, like calling update but with the same rule as | for which side wins on duplicate keys. Only the left dict is reassigned in place; the right dict is unchanged.
left = {'fruit': 'Apple', 'calories': 100}
right = {'vegetable': 'Tomato', 'calories': 50}
left |= right
print(left)After |=, left contains both originals’ keys and calories is 50. Use this when you intentionally want to grow one dict you already own.
Merge dictionaries using update()
dict.update(other) pulls key–value pairs from other into the dict you call it on. Duplicate keys are overwritten by values from other. Unlike |, this method returns None; it always mutates the receiver.
d1 = {'fruit': 'Apple', 'calories': 100}
d2 = {'vegetable': 'Tomato', 'calories': 50}
d1.update(d2)
print(d1)d1 ends as {'fruit': 'Apple', 'calories': 50, 'vegetable': 'Tomato'}. This works on all Python 3 versions and is the traditional in-place merge.
Merge dictionaries without changing the original dictionaries
When callers must not see your merge mutate their dicts, build a new mapping (or merge into a copy). Two common patterns are copy() plus update, and dict unpacking.
Using copy() and update()
copy() (shallow copy) duplicates the top-level dict object so you can update the duplicate without touching the original.
def merge_dicts(a, b):
out = a.copy()
out.update(b)
return out
d1 = {'fruit': 'Apple', 'calories': 100}
d2 = {'vegetable': 'Tomato', 'calories': 50}
result = merge_dicts(d1, d2)
print('d1:', d1)
print('result:', result)d1 stays unchanged; result holds the merged view. This pattern was the usual approach before PEP 448-style unpacking became widespread.
Using dictionary unpacking (``)
From Python 3.5 onward, you can unpack mappings into a new dict literal. Later unpackings override earlier keys, left to right.
d1 = {'name': 'Ram', 'employeeid': 2254}
d2 = {'city': 'Pune', 'state': 'Maharashtra'}
z = {**d1, **d2}
print(z)If keys overlap, the rightmost wins: {**d1, **d2} matches the duplicate-key rule of d1 | d2 for plain dicts. This is still the most portable “new dict” merge on Python 3.5–3.8.
Which dictionary merge method should you use?
Use a | b on 3.9+ when you want a clear, symmetric “new merged dict” and both operands are mappings. Use {**a, **b} when you must support Python 3.8 or need to merge more than two literals in one expression. Use a.update(b) or a |= b when the left dict is your canonical accumulator and in-place updates are what you want. Use a.copy() + update when you need an explicit, step-by-step merge that reads well in older codebases.
What happens when dictionaries have duplicate keys?
Python keeps at most one value per key. Any merge that combines two sources assigns one winner per key. For a | b, {**a, **b}, and a.update(b), the later source controls the value for shared keys (b wins in those examples). ChainMap is different: lookup walks the chain left to right and returns the first hit, and dict(chainmap) builds a snapshot using that same precedence for overlapping keys.
from collections import ChainMap
base = {'id': 1, 'label': 'base'}
patch = {'id': 99, 'note': 'patch'}
print('base | patch :', base | patch)
print('{**base, **patch}:', {**base, **patch})
cm = ChainMap(base, patch)
print('cm["id"] :', cm['id'])
print('dict(cm) :', dict(cm))base | patch and {**base, **patch} both show 'id': 99 because patch is applied second. ChainMap(base, patch) checks base first, so cm['id'] is 1 and dict(cm) keeps that value for 'id' while still adding 'note' from patch.
Merge more than two dictionaries
You can chain the merge operator: a | b | c (3.9+). With unpacking, order is explicit: {**a, **b, **c}. For in-place accumulation, call base.update(b); base.update(c) or loop over a list of dicts. Each step applies the same duplicate-key rule (right over left in | and in unpacking order).
a = {'x': 1}
b = {'y': 2}
c = {'z': 3, 'x': 99}
print(a | b | c)
print({**a, **b, **c})The printed merged dicts place 'x': 99 from c, since it appears last.
Merge nested dictionaries in Python
Shallow merge vs deep merge
Operators and unpacking only merge top-level keys. If both dicts contain the same key whose value is another dict, the inner dict is replaced as a whole, not field-by-field merged.
A = {'x': {'n': 1}}
B = {'x': {'n': 2}}
print(A | B)
print('A after:', A)You still see A unchanged, but the merged result’s 'x' is exactly B’s inner dict. For true deep merges (recursive union of nested dicts), use a dedicated recursive function, copy.deepcopy plus careful updates, or a library—stdlib merge operations will not infer nested intent for you.
Merge dictionaries without copying using ChainMap
collections.ChainMap treats multiple dicts as a search stack: __getitem__ walks them in order and returns the first hit. It does not copy data into one dict by default, which keeps memory cheap when layers override only a few keys.
from collections import ChainMap
defaults = {'theme': 'light', 'timeout': 30}
overrides = {'timeout': 60}
cm = ChainMap(overrides, defaults)
print(cm['timeout'])
print(dict(cm))cm['timeout'] is 60 from overrides. dict(cm) builds a single merged snapshot if you need a plain dict. For layered configuration and “fallback” chains, ChainMap fits better than repeatedly copying dicts.
Methods you should usually avoid
Lambda expression for merging dictionaries
You can wedge a merge into a lambda that copies and updates in one expression, but it hides control flow, confuses readers, and offers no performance win over a small named function or {**a, **b}.
d1 = {'fruit': 'Apple', 'calories': 100}
d2 = {'vegetable': 'Tomato', 'calories': 50}
merge = (lambda l=d1.copy(): (l.update(d2), l)[1])()
print(merge)Prefer a normal function or a direct merge expression so stack traces and reviews stay clear.
itertools.chain() for merging dictionaries
itertools.chain(d1.items(), d2.items()) feeds dict(...) a stream of pairs. It works, but it is easy to misread, no faster than clearer options for normal sizes, and still subject to the same duplicate-key rules as other shallow merges.
from itertools import chain
d1 = {'fruit': 'Apple', 'calories': 100}
d2 = {'vegetable': 'Tomato', 'calories': 50}
print(dict(chain(d1.items(), d2.items())))Reach for |, **, or update unless you already have an iterator of pairs for other reasons.
Python dictionary merge quick reference table
| Approach | Produces new dict? | Mutates left dict? | Typical Python | Duplicate keys |
|---|---|---|---|---|
a | b |
Yes | No | 3.9+ | Right (b) wins |
a |= b |
No (updates a) |
Yes | 3.9+ | Right wins |
{**a, **b} |
Yes | No | 3.5+ | Rightmost wins |
a.update(b) |
No | Yes | 3.x | Values from b win |
a.copy(); copy.update(b) |
New object from copy | Copy only | 3.x | Same as update |
ChainMap then dict(...) |
New dict if you call dict |
No (until materialized) | 3.x | Lookups use first dict in chain; dict(cm) keeps first mapping’s value on duplicate keys |
Summary
Merging Python dictionaries is mostly about three decisions: whether you need a new dict, which side should win when keys collide, and whether you are only merging top-level keys. Use | and |= on Python 3.9+ for readable merge semantics; use {**a, **b} or copy plus update for compatibility and clarity. Remember that nested dicts are not merged recursively by these tools. For layered lookup without eager copying, prefer ChainMap, and skip lambda or chain tricks that obscure the same shallow merge.
References
Frequently Asked Questions
1. What is the simplest way to merge two dictionaries in modern Python?
merged = a | b; for older versions, {**a, **b} or a.copy() followed by a.update(b) are common choices.2. What happens to duplicate keys when merging two Python dictionaries?
a | b and {**a, **b}, values from b replace the same keys from a; a.update(b) overwrites keys in a in the same way.3. How do I merge dictionaries without changing the originals?
a | b, {**a, **b}, or start from a.copy() and call update on the copy—avoid update or |= on the dict you need to preserve.4. Does merging dictionaries in Python perform a deep merge of nested dicts?
|, ** unpacking, and update only do a shallow merge at the top level; nested dict values are replaced by reference, so use an explicit recursive strategy, copy.deepcopy, or a library if you need deep merging.
