ChainMap.new_child / parents
Both return NEW ChainMaps that share the same underlying dicts. new_child puts a fresh (or given) mapping in front, so writes stay local; parents drops the front mapping — like leaving a scope.
Common call
local = scope.new_child() · outer = local.parents
Returns
new ChainMaps; the original is unchanged
Replaces
copying a whole dict to shadow a few keys
Watch out
parents of a one-map chain is ChainMap({}) — a new empty dict
ChainMap.new_child(mm — The mapping to put in front; None means a new empty dict (3.4+).type: mapping | None · default: None=None, **kwargs)
→ ChainMap
Demo
Live evaluation
An inner scope shadows the outer one; parents gets the outer view back.
Try:
Inputs
alist[str]outer names
blist[str]inner names
Code
from collections import ChainMap outer = ChainMap(dict.fromkeys(['x', 'y'], 'outer')) inner = outer.new_child(dict.fromkeys(['y', 'z'], 'inner')) (dict(inner), inner.parents)
Result
({'x': 'outer', 'y': 'inner', 'z': 'inner'}, ChainMap({'x': 'outer', 'y': 'outer'}))
In "shadowing" y resolves to "inner" in the child, while inner.parents is the original outer chain with y still "outer". In the second tab the assignment goes into the new front dict, so parents shows the base mapping unchanged.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| m | mapping | None | no (None) | The mapping to put in front; None means a new empty dict (3.4+). |
| **kwargs | values | no | Keys to set in the new front mapping (3.10+). With m given, they update m itself. |
Return value
ChainMap — new_child: ChainMap(m, *self.maps). parents: ChainMap(*self.maps[1:]).
Common patterns
Enter and leave a scope
Rebind the name on entry and exit.
scope = scope.new_child() try: run_block(scope) finally: scope = scope.parents
Temporary overrides
Keyword arguments build the front mapping (3.10+).
debug_config = config.new_child(debug=True, log_level="DEBUG")
Skip the local scope on lookup
parents searches everything except maps[0].
outer_value = scope.parents[name]
Examples
1. new_child with no mapping
from collections import ChainMap
ChainMap({'a': 1}).new_child()
Returns
ChainMap({}, {'a': 1})2. new_child with keyword values
from collections import ChainMap
ChainMap({'a': 1}).new_child(a=2)['a']
Returns
23. parents drops maps[0]
from collections import ChainMap
ChainMap({'a': 1}, {'b': 2}).parents
Returns
ChainMap({'b': 2})4. parents of a single map
from collections import ChainMap
ChainMap({'a': 1}).parents
Returns
ChainMap({})5. The original is not changed
from collections import ChainMap
base = ChainMap({'a': 1})
child = base.new_child({'a': 2})
(base['a'], child['a'])
Returns
(1, 2)6. Mappings are shared
from collections import ChainMap
d = {'a': 1}
ChainMap(d).new_child().maps[1] is d
Returns
TruePitfalls
1. Calling parents like a method
parents is a property.
cm.parents()
from collections import ChainMap ChainMap({}, {'a': 1}).parents()
TypeError: 'ChainMap' object is not callable
cm.parents
from collections import ChainMap ChainMap({}, {'a': 1}).parents
ChainMap({'a': 1})
2. Forgetting to rebind
new_child returns a new ChainMap; the old variable still points at the old chain.
call only
from collections import ChainMap cm = ChainMap({'a': 1}) cm.new_child({'a': 2}) cm['a']
1
cm = cm.new_child(...)
from collections import ChainMap cm = ChainMap({'a': 1}) cm = cm.new_child({'a': 2}) cm['a']
2
When to use
Use it
- Interpreters, template engines and config systems with nested scopes
- Trying out overrides without touching the base settings
Reach for something else
- Deeply nested chains on hot paths → lookups get slower with every layer
Notes
CPython impl
new_child returns self.__class__(m, *self.maps); parents returns self.__class__(*self.maps[1:])
Versions
m parameter 3.4, keyword arguments 3.10 (docs.python.org)
FAQ
It returns a new ChainMap with a mapping in front of the existing ones: a new empty dict by default, or the mapping you pass. Lookups see the new mapping first and all writes go into it.