d
is rebound; the variable is updated to point to val
in each loop.
For each key
in keys
, either the key is found (val = d[key]
succeeds) or the default_factory()
is used to create a new value for that key.
If the key was found but the value was not a MutableMapping
type, the found value is replaced with a new default_factory()
result.
Once the new value has been determined for this level, d
is told to forget about the old dictionary and pointed to the new instead.
Rebinding does not change the old value. It merely stops referring to that old value.
Let's use a simple example:
>>> d = {'foo': {}}
>>> keys = ['foo']
>>> newkey = 'bar'
>>> newval = 'eggs'
>>> original = d
At the start, original
and d
are the same object. Think of names here as paper labels, and their values as balloons. The labels are tied with string to the balloons. In the above example, the d
and original
labels are both tied to the same dictionary balloon.
When we enter the for key in keys
loop, the d[key]
lookup succeeds and val
is tied to the result of d['foo']
, an empty dictionary:
>>> key = keys[0]
>>> key
'foo'
>>> val = d[key]
>>> val
{}
This is a regular Python dictionary, and isinstance(val, MutableMapping)
is True
. Next line rebinds the d
label to that dictionary. The string is simply untied from the original dictionary and now attached to the same balloon val
is tied to:
>>> d = val
>>> d
{}
>>> original
{'foo': {}}
>>> d is val
True
>>> d is original
False
The original dictionary was not altered by the rebinding!
Having run out of keys (there was only one in keys
), the next part then assigns newval
to d[newkey]
:
>>> d[newkey] = newval
>>> d
{'bar': 'eggs'}
However, d
is not the only label attached to this dictionary balloon. Dictionaries themselves contain keys and values, both of which are labels that are tied to balloons too! The original
label is still tied to the outer dictionary balloon, and it has a foo
key associated value, which was tied to a nested dictionary, and it is this nested dictionary we just changed:
>>> original
{'foo': {'bar': 'eggs'}}
The algorithm merely followed along labels via strings to new dictionaries.
Using more complex key combinations just means more strings are being followed, with perhaps an extra dictionary being pumped up to be tied in.