Question: Could someone explain the output? Why is z
equal to 2
in the second print()
?
Code:
x=1
y=2
x,y,z=x,x,y
print(y,x,y,z)
z,y,z=x,y,z
print(x,y,z)
Output:
1 1 1 2
1 1 2
Python tuple assignment uses a stack, so assuming x=1 and y=2:
x,y,z=x,x,y
translates abstractly to:
push x (value 1) on stack: top_of_stack(TOS) -> 1
push x (value 1) on stack: TOS -> 1, 1
push y (value 2) on stack: TOS -> 2, 1, 1
reverse top 3 stack entries: TOS -> 1, 1, 2
pop stack and store in x (x=1) TOS -> 1, 2
pop stack and store in y (y=1) TOS -> 2
pop stack and store in z (z=2) TOS -> empty
final result is x=1, y=1, z=2, next line:
z,y,z=x,y,z
pushes x,y,z (1,1,2), then loads z=1, then y=1, then z=2 (overwriting z=1).
Here's the actual disassembly with comments:
>>> dis.dis('x=1;y=2;x,y,z=x,x,y;z,y,z=x,y,z')
1 0 LOAD_CONST 0 (1) # load constant 1
2 STORE_NAME 0 (x) # assign to x
4 LOAD_CONST 1 (2) # load constant 2
6 STORE_NAME 1 (y) # assign to y
8 LOAD_NAME 0 (x) # push x on stack (1)
10 LOAD_NAME 0 (x) # push x again on stack (1)
12 LOAD_NAME 1 (y) # push y on stack (2)
14 ROT_THREE # two instructions reverse stack
16 ROT_TWO # .. 2,1,1 becomes 1,1,2
18 STORE_NAME 0 (x) # pop x=1
20 STORE_NAME 1 (y) # pop y=1
22 STORE_NAME 2 (z) # pop z=2
24 LOAD_NAME 0 (x) # push x (1)
26 LOAD_NAME 1 (y) # push y (1)
28 LOAD_NAME 2 (z) # push z (2)
30 ROT_THREE # reverse stack
32 ROT_TWO # 2,1,1 becomes 1,1,2
34 STORE_NAME 2 (z) # pop z=1 <---
36 STORE_NAME 1 (y) # pop y=1 \
38 STORE_NAME 2 (z) # pop z=2 (overwriting previous)
You can also think of this more abstractly as:
So:
x=1
y=2
x,y,z=x,x,y
Means:
# x,y,z=1,1,2
x=1
y=1
z=2
Then:
z,y,z=x,y,z
Means:
# z,y,z = 1,1,2
z=1
y=1
z=2 # overwriting previous z=1