Here is my Python code that creates an infinitely nested dictionary:
a = a['k'] = {}
print(a)
print(a['k'])
print(a['k']['k'])
print(a is a['k'])
Here is the output:
{'k': {...}}
{'k': {...}}
{'k': {...}}
True
The output shows that a['k']
refers to a
itself which makes it infinitely nested.
I am guessing that the statement:
a = a['k'] = {}
is behaving like:
new = {}
a = new
a['k'] = new
which would indeed create an infinitely nested dictionary.
I looked at Section 7.2: Assignment statements of The Python Language Reference but I couldn't find anything that implies that a = a['k'] = {}
should first set a
to the new dictionary and then insert a key/value pair in that dictionary. Here are some excerpts from the reference that I found relevant but did not answer my question:
If the target list is a single target with no trailing comma, optionally in parentheses, the object is assigned to that target.
If the target is a subscription: The primary expression in the reference is evaluated. It should yield either a mutable sequence object (such as a list) or a mapping object (such as a dictionary). Next, the subscript expression is evaluated.
If the primary is a mapping object (such as a dictionary), the subscript must have a type compatible with the mapping’s key type, and the mapping is then asked to create a key/datum pair which maps the subscript to the assigned object. This can either replace an existing key/value pair with the same key value, or insert a new key/value pair (if no key with the same value existed).
Each of these excerpts define the behaviour of an assignment with a single target such as a = {}
and a['k'] = {}
but they don't seem to talk about what should happen in case of a = a['k'] = {}
. Where is the order of evaluation for such a statement documented?
This question is now resolved. GPhilo's answer pointed to the relevant clause of Section 7.2: Assignment statements. The relevant clause was right at the beginning but I had overlooked it earlier. Here it is:
An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.
Let us compare it with the grammar now.
The assignment statement is defined as
assignment_stmt ::= (target_list "=")+ (starred_expression | yield_expression)
So the statement
a = a['k'] = {}
has two target_list
elements, i.e., a
and a['k']
, and a starred_expression
element, i.e., {}
, so {}
is assigned to each of the target lists a
and a['k']
from left to right.
assignment_stmt ::= (target_list "=")+ (starred_expression | yield_expression)
, soa = a['k'] = {}
has twotarget_list
elements (a
anda['k']
) and astarred_expression
element ({}
), so{}
is assigned to each of the target listsa
anda['k']
from left to right. – Judsonjudus