6

I had the following line in a loop occurring during the initialization of a singly linked list class:

previous = previous.pointer = Node(item, None)

The intended semantics was what I can obtain with:

previous.pointer = Node(item, None)
previous = previous.pointer

What I found out using pdb is that previous gets reassigned to the new Node object. And the (former) previous's pointer attribute is unchanged.

I couldn't find documentation about the expected behaviour of this kind of assignment.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130

2 Answers2

4

This is well explained in the documentation:

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.

(emphasis mine)

Where the term target_list is used in the grammar as follows:

assignment_stmt ::=  (target_list "=")+ (expression_list | yield_expression)

(Note the + sign after the first parenthesis - this allows chain assignments)

Thus, the resulting semantics:

target_list1 = target_list2 = expression

is equivalent to:

target_list1 = expression
target_list2 = expression

There is no way of confusing what is being assigned (evaluates the expression list) with what is the target of the assignment, because assignment is a statement, not an expression. Hence, all with = in it, will not be treated as an expression - only the right most part. Next, all assignment statements will be processed left to right (i.e. their target lists will have the expression's value assigned).

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
2

It should assign both, previous.pointer and previous to the newly created Node, effectively at the same time1.

1I'm not sure which one gets assigned first (or if that's even defined by the specification -- though it should only matter in the case of descriptors like the builtin property).

mgilson
  • 300,191
  • 65
  • 633
  • 696