How to Use ChainMap for Layered Config Lookup in Python
This code demonstrates using collections.ChainMap to combine multiple dictionaries into a single layered lookup, where earlier maps override later ones.
Python code
21 linesfrom collections import ChainMap
defaults = {"theme": "light", "lang": "en", "debug": False}
user = {"lang": "de", "auto_save": True}
runtime = {"debug": True}
config = ChainMap(runtime, user, defaults)
if __name__ == "__main__":
print("theme:", config["theme"])
print("lang:", config["lang"])
print("debug:", config["debug"])
print("auto_save:", config["auto_save"])
print("missing key ->", end=" ")
try:
print(config["unknown"])
except KeyError:
print("KeyError: 'unknown'")
# Show layered resolution
print("\nMaps order:", list(config.maps))
Output
theme: light
lang: de
debug: True
auto_save: True
missing key -> KeyError: 'unknown'
Maps order: [{'debug': True}, {'lang': 'de', 'auto_save': True}, {'theme': 'light', 'lang': 'en', 'debug': False}]
How it works
ChainMap groups multiple dicts into one view without copying data. Lookups search each map in order, using the value from the first map containing the key. This is perfect for layered configs: runtime settings override user settings, which override defaults. Mutating the ChainMap only affects the first map, keeping the underlying defaults pristine. The order of maps is visible via the .maps attribute, and missing keys raise a KeyError like a normal dict.
Common mistakes
- Assuming later maps override earlier ones; ChainMap searches maps from first to last.
- Forgetting that `update()` on a ChainMap only modifies the first map, not all.
- Expecting `ChainMap` to deep-merge nested dictionaries; it only handles top-level keys.
- Using `config['key'] = value` when you want to modify a different map than the first.
Variations
- Use `dict(runtime, **user)` to merge dictionaries, but copying loses the layering.
- Use `ChainMap` with `new_child()` to add a temporary overrides layer without mutating the original.
Real-world use cases
- Merge environment variables, user settings, and default configs in a CLI app.
- Implement a language translation lookup where fallback languages are tried in order.
- Layer permission scopes so user-level settings override tenant defaults.
Sponsored
More from Dictionaries & sets
- Build a Case-Insensitive Dict with a Wrapper Class in Python medium
- Build a defaultdict histogram of categories in Python easy
- Build adjacency dict graph from edges in Python easy
- Build an OrderedDict insertion order demo in Python 3 easy
- Check Invertible Mapping for Duplicate Values in Python easy
- Compare Two Dictionaries in Python easy
Keep learning
Related tutorials and quizzes for this topic.