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.

Easy Python 3.9+ Aug 9, 2026 Dictionaries & sets 14 views 0 copies

Python code

21 lines
Python 3.9+
from 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

stdout
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

  1. Use `dict(runtime, **user)` to merge dictionaries, but copying loses the layering.
  2. 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

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Dictionaries & sets

Related tutorials and quizzes for this topic.