I found the assignment a = a[1:] = [2]
in an article. I tried it in python3 and python2; it all works, but I don't understand how it works. =
here is not like in C; C processes =
by right to left. How does python process the =
operator?

- 76,765
- 14
- 60
- 81

- 1,247
- 1
- 10
- 19
-
I reopened this question because it is a much more complex case than the typical `x = y = some_func()` case addressed in [How do chained assignments work?](https://stackoverflow.com/q/7601823/364696) – ShadowRanger Feb 06 '18 at 01:12
-
2It can be left to right because assignment is a type of statement in Python and not an expression like in C. It doesn’t have an associativity since `a = b = … = x` is all parsed together. – Ry- Feb 06 '18 at 01:15
-
The question is only related to the non-complex part though (left-to-right). OP states they understand how it works. I am not strongly against reopening though. – ayhan Feb 06 '18 at 01:18
2 Answers
Per the language docs on assignment:
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.
In this case, a = a[1:] = [2]
has an expression list [2]
, and two "target lists", a
and a[1:]
, where a
is the left-most "target list".
You can see how this behaves by looking at the disassembly:
>>> import dis
>>> dis.dis('a = a[1:] = [2]')
1 0 LOAD_CONST 0 (2)
2 BUILD_LIST 1
4 DUP_TOP
6 STORE_NAME 0 (a)
8 LOAD_NAME 0 (a)
10 LOAD_CONST 1 (1)
12 LOAD_CONST 2 (None)
14 BUILD_SLICE 2
16 STORE_SUBSCR
18 LOAD_CONST 2 (None)
20 RETURN_VALUE
(The last two lines of the disassembly can be ignored, dis
is making a function wrapper to disassemble the string)
The important part to note is that when you do x = y = some_val
, some_val
is loaded on the stack (in this case by the LOAD_CONST
and BUILD_LIST
), then the stack entry is duplicated and assigned, from left to right, to the targets given.
So when you do:
a = a[1:] = [2]
it makes two references to a brand new list
containing 2
, and the first action is a STORE
one of these references to a
. Next, it stores the second reference to a[1:]
, but since the slice assignment mutates a
itself, it has to load a
again, which gets the list
just stored. Luckily, list
is resilient against self-slice-assignment, or we'd have issues (it would be forever reading the value it just added to add to the end until we ran out of memory and crashed); as is, it behaves as a copy of [2]
was assigned to replace any and all elements from index one onwards.
The end result is equivalent to if you'd done:
_ = [2]
a = _
a[1:] = _
but it avoids the use of the _
name.
To be clear, the disassembly annotated:
Make list [2]
:
1 0 LOAD_CONST 0 (2)
2 BUILD_LIST 1
Make a copy of the reference to [2]
:
4 DUP_TOP
Perform store to a
:
6 STORE_NAME 0 (a)
Perform store to a[1:]
:
8 LOAD_NAME 0 (a)
10 LOAD_CONST 1 (1)
12 LOAD_CONST 2 (None)
14 BUILD_SLICE 2
16 STORE_SUBSCR

- 143,180
- 12
- 188
- 271
The way I understand such assignments is that this is equivalent to
temp = [2]
a = temp
a[1:] = temp
The resulting value of [2, 2]
is consistent with this interpretation.

- 76,765
- 14
- 60
- 81