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?
Chained assignment with views and copiesThe act of selecting rows or columns to access from a dataframe or series is called indexing. The flexibility of pandas allows for chained indexing, where you can repeatedly index the outcome of a previous indexing operation.
Chained assignment A statement like w = x = y = z is called a chained assignment in which the value of z is assigned to multiple variables w, x, and y . Chained assignments are often used to initialize multiple variables, as in.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With