Batu Lab NotesPractical developer guides

Merge a local override into nested configuration lookups

By Batu · English technical notes

Also published in our Blogger archive.

Merge a local override into nested configuration lookups

By Batu. AI assistance was used to prepare this article.

collections.ChainMap provides one mapping-like lookup view across several mappings. It searches its maps from left to right, so new_child(local) is a useful way to put a short-lived local override ahead of an existing environment-and-default chain. This avoids copying a merged dictionary when the desired behavior is simply “first value found wins.”

from collections import ChainMap

defaults = {"host": "127.0.0.1", "port": 8000, "debug": False}
environment = {"port": 8080, "debug": True}
base_config = ChainMap(environment, defaults)

local = {"port": 9000}
config = base_config.new_child(local)
config["debug"] = False

assert config["host"] == "127.0.0.1"
assert config["port"] == 9000
assert config["debug"] is False
assert local == {"port": 9000, "debug": False}

print(f"host={config['host']}")
print(f"port={config['port']}")
print(f"debug={config['debug']}")
print(f"local={local}")

Expected stdout

host=127.0.0.1
port=9000
debug=False
local={'port': 9000, 'debug': False}

The host lookup falls through the local and environment mappings to defaults. port comes from local, and assigning config["debug"] writes only to the first map, which is why local gains that key. The original environment mapping remains unchanged.

This is a lookup overlay, not a recursive configuration merge. If defaults["database"] and local["database"] are both dictionaries, the local dictionary replaces the whole top-level value rather than selectively combining nested keys. Missing keys raise KeyError, just as with a normal dictionary. ChainMap also keeps references to its input mappings, so a later mutation of environment or defaults is visible through config; make copies first when a snapshot is required.

Source: Python ChainMap documentation.