Merge Dictionaries in Python: |, update(), **, and More

Learn how to merge dictionaries in Python using the | operator, update(), ** unpacking, copy(), ChainMap, and more, with duplicate key behavior and Python version differences.

Published

Updated

Read time 7 min read

Reviewed byDeepak Prasad

Merge Dictionaries in Python: |, update(), **, and More

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.

python
d1 = {'fruit': 'Apple', 'calories': 100}
d2 = {'vegetable': 'Tomato', 'calories': 50}
result = d1 | d2
print('d1 unchanged:', d1)
print('merged:', result)
Output

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.

python
left = {'fruit': 'Apple', 'calories': 100}
right = {'vegetable': 'Tomato', 'calories': 50}
left |= right
print(left)
Output

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.

python
d1 = {'fruit': 'Apple', 'calories': 100}
d2 = {'vegetable': 'Tomato', 'calories': 50}
d1.update(d2)
print(d1)
Output

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.

python
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)
Output

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.

python
d1 = {'name': 'Ram', 'employeeid': 2254}
d2 = {'city': 'Pune', 'state': 'Maharashtra'}
z = {**d1, **d2}
print(z)
Output

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.

python
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))
Output

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).

python
a = {'x': 1}
b = {'y': 2}
c = {'z': 3, 'x': 99}
print(a | b | c)
print({**a, **b, **c})
Output

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.

python
A = {'x': {'n': 1}}
B = {'x': {'n': 2}}
print(A | B)
print('A after:', A)
Output

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.

python
from collections import ChainMap

defaults = {'theme': 'light', 'timeout': 30}
overrides = {'timeout': 60}
cm = ChainMap(overrides, defaults)
print(cm['timeout'])
print(dict(cm))
Output

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}.

python
d1 = {'fruit': 'Apple', 'calories': 100}
d2 = {'vegetable': 'Tomato', 'calories': 50}
merge = (lambda l=d1.copy(): (l.update(d2), l)[1])()
print(merge)
Output

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.

python
from itertools import chain

d1 = {'fruit': 'Apple', 'calories': 100}
d2 = {'vegetable': 'Tomato', 'calories': 50}
print(dict(chain(d1.items(), d2.items())))
Output

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?

For Python 3.9 and later, use the merge operator to build a new dict: 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?

Later mappings win: in 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?

Build a new dict with 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?

No—|, ** 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.

5. When should I use collections.ChainMap instead of merging?

Use ChainMap when you want several dicts searched in order without building a new combined dict yet; it is ideal for layered defaults and lookups, not as a drop-in for “one frozen merged snapshot.”
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …