collections.ChainMap

The classic use is layered settings — command line over environment over defaults — without merging anything. The mappings are kept by reference in .maps, so later changes to them show through.

collections classPython 3.3+Live demo
Common call
ChainMap(user_settings, defaults)
Returns
the first value found for each key
Replaces
{**defaults, **user_settings} when you need live updates
Watch out
cm[key] = v always writes into maps[0]
collections.ChainMap(*maps)
→ ChainMap

Demo

Live evaluation
Keys in the first mapping win. len() counts each distinct key once.
Try:
Inputs
userlist[str]keys set by the user
defaultslist[str]keys with defaults
Code
from collections import ChainMap
settings = ChainMap(dict.fromkeys(['color'], 'user'), dict.fromkeys(['color', 'size', 'font'], 'default'))
(dict(settings), len(settings))
Result
({'color': 'user', 'size': 'default', 'font': 'default'}, 3)

dict(settings) lists keys in the order of the LAST mapping first (defaults) with later-added keys after — but every value comes from the first mapping that has the key, so color is "user". In the writes tab the key a exists in the second map, yet the assignment creates a new a in maps[0] and leaves the old one untouched.

Parameters

NameTypeRequiredDescription
*mapsmappingsnoSearched first to last. The first one receives all writes and deletions.

Return value

ChainMap — A view over the given mappings (not a copy); with no arguments, over one new empty dict.

Attributes

AttributeTypeMeaning
mapslistThe underlying mappings, first searched first. Public and mutable.
get(key, default=None)methodLookup through all maps with a default instead of KeyError.
copy()methodNew ChainMap with a shallow copy of maps[0] and the same other maps.
fromkeys(iterable, value=None)classmethodChainMap over one new dict built by dict.fromkeys.

Common patterns

Command line over environment over defaults
The docs recipe for layered configuration.
import os
from collections import ChainMap
config = ChainMap(cli_args, os.environ, defaults)
Nested scopes
new_child() pushes a scope, .parents pops it.
from collections import ChainMap
scope = ChainMap()
scope = scope.new_child({"x": 1})
scope = scope.parents
Flatten when done
dict() takes a snapshot with the correct precedence.
snapshot = dict(config)

Examples

1. First mapping wins
from collections import ChainMap ChainMap({'x': 1}, {'x': 2, 'y': 3})['x']
Returns
1
2. Falls through to later maps
from collections import ChainMap ChainMap({'x': 1}, {'x': 2, 'y': 3})['y']
Returns
3
3. repr shows every map
from collections import ChainMap ChainMap({'a': 1}, {'b': 2})
Returns
ChainMap({'a': 1}, {'b': 2})
4. get with a default
from collections import ChainMap ChainMap({'a': 1}).get('z', 0)
Returns
0
5. Live view, not a copy
from collections import ChainMap defaults = {'size': 'M'} cm = ChainMap({}, defaults) defaults['size'] = 'L' cm['size']
Returns
'L'
6. copy() copies only maps[0]
from collections import ChainMap base = {'b': 2} c2 = ChainMap({'a': 1}, base).copy() c2.maps[1] is base
Returns
True
7. fromkeys
from collections import ChainMap ChainMap.fromkeys('ab', 0)
Returns
ChainMap({'a': 0, 'b': 0})

Pitfalls

1. Expecting writes to update the mapping that holds the key
Writes go to maps[0]. To change a lower layer, write to it directly (cm.maps[i][key] = v).
cm[key] = v
from collections import ChainMap
defaults = {'size': 'M'}
cm = ChainMap({}, defaults)
cm['size'] = 'L'
defaults
{'size': 'M'}
cm.maps[1][key] = v
from collections import ChainMap
defaults = {'size': 'M'}
cm = ChainMap({}, defaults)
cm.maps[1]['size'] = 'L'
defaults
{'size': 'L'}
2. Merging with dict unpacking when you need live data
{**a, **b} is a snapshot; later changes to a or b are not seen. ChainMap reads through.
{**user, **defaults}
user, defaults = {}, {'x': 1}
merged = {**defaults, **user}
user['x'] = 2
merged['x']
1
ChainMap(user, defaults)
from collections import ChainMap
user, defaults = {}, {'x': 1}
merged = ChainMap(user, defaults)
user['x'] = 2
merged['x']
2

When to use

Use it
  • Layered configuration with precedence
  • Variable scopes in interpreters and template engines
  • Temporary overrides that must not modify the originals
Reach for something else
  • A one-time merge → {**a, **b} or a | b (3.9+)
  • Very many layers on a hot path → lookups walk the maps in order

Notes

CPython impl
Lib/collections/__init__.py — a MutableMapping over self.maps; not a dict subclass
Iteration
Keys are yielded in dict.fromkeys order over the maps from LAST to first, so the deepest map's keys come first
Versions
Added in 3.3; | and |= operators 3.9 (docs.python.org)

FAQ

Treating several dicts as one without copying them: lookups search the mappings in order and return the first hit. It is typically used for layered settings (user > environment > defaults) and for nested scopes.