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.
Demo
from collections import ChainMap settings = ChainMap(dict.fromkeys(['color'], 'user'), dict.fromkeys(['color', 'size', 'font'], 'default')) (dict(settings), len(settings))
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
| Name | Type | Required | Description |
|---|---|---|---|
| *maps | mappings | no | Searched 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
| Attribute | Type | Meaning |
|---|---|---|
| maps | list | The underlying mappings, first searched first. Public and mutable. |
| get(key, default=None) | method | Lookup through all maps with a default instead of KeyError. |
| copy() | method | New ChainMap with a shallow copy of maps[0] and the same other maps. |
| fromkeys(iterable, value=None) | classmethod | ChainMap over one new dict built by dict.fromkeys. |
Common patterns
import os from collections import ChainMap config = ChainMap(cli_args, os.environ, defaults)
from collections import ChainMap scope = ChainMap() scope = scope.new_child({"x": 1}) scope = scope.parents
snapshot = dict(config)
Examples
Pitfalls
from collections import ChainMap defaults = {'size': 'M'} cm = ChainMap({}, defaults) cm['size'] = 'L' defaults
from collections import ChainMap defaults = {'size': 'M'} cm = ChainMap({}, defaults) cm.maps[1]['size'] = 'L' defaults
user, defaults = {}, {'x': 1} merged = {**defaults, **user} user['x'] = 2 merged['x']
from collections import ChainMap user, defaults = {}, {'x': 1} merged = ChainMap(user, defaults) user['x'] = 2 merged['x']
When to use
- Layered configuration with precedence
- Variable scopes in interpreters and template engines
- Temporary overrides that must not modify the originals
- 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
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.