Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a = a['k'] = {} create an infinitely nested dictionary?

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.

like image 482
Susam Pal Avatar asked Feb 21 '19 13:02

Susam Pal


People also ask

How are the nested dictionaries created?

Creating a Nested Dictionary In Python, a Nested dictionary can be created by placing the comma-separated dictionaries enclosed within braces.

How do you loop a nested dictionary?

Iterate over all values of a nested dictionary in python We can achieve all this in a simple manner using recursion. Using the function nested_dict_pair_iterator() we iterated over all the values of a dictionary of dictionaries and printed each pair including the parent keys.

What is the use of nested dictionary?

It is used to store the data values in key-value pairs. Nesting Dictionary means putting a dictionary inside another dictionary. Nesting is of great use as the kind of information we can model in programs is expanded greatly. A nested dictionary contains an unordered collection of various dictionaries.

Is nested dictionary possible?

Key Points to Remember: Nested dictionary is an unordered collection of dictionary. Slicing Nested Dictionary is not possible. We can shrink or grow nested dictionary as need. Like Dictionary, it also has key and value.


1 Answers

Assignments in an assignment statement are resolved from left to right, as per the section 7.2 you quoted (emphasis mine):

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.

That means that yes, indeed your statement is equivalent to:

new = {}
a = new
a['k'] = new

As a quick counter-proof, swapping the order of the assignments results in error:

a['k'] = a = {}

raises

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
like image 183
GPhilo Avatar answered Sep 27 '22 21:09

GPhilo