Reputation: 23
I am new to Python and the following question is so difficult for me to understand.
a,b,c=1,2,3
a,b,c=c,a,b=b,a,c=c,b,a
print(a,b,c)
The output of this is -
(2,3,1)
but I don't understand why it isn't -
(3,2,1)
Upvotes: 2
Views: 2505
Reputation: 4544
As norok indicated, storage and loading happen from different directions. If we take the following code we can see what python is doing under the hood.
import dis
def foo():
a, b, c = 1, 2, 3
a, b, c = c, a, b = b, a, c = c, b, a
dis.dis(foo)
Below you see the bytecode. To the right of the comments, you see the values for variables a
, b
, and c
as well as the memory stack at the end of the operation. You'll see the DUP_TOP
command negate the assignments at various steps so only the first load and last store appear to do anything. This would also explain why a, b, c = a, a, a = b, b, b = c, c, c = b, a, c = c, b, a
still evaluates to (2, 3, 1)
.
# a b c stack
4 0 LOAD_CONST 4 ((1, 2, 3)) # - - - [(1, 2, 3)]
3 UNPACK_SEQUENCE 3 # - - - [1, 2, 3]
6 STORE_FAST 0 (a) # 1 - - [2, 3]
9 STORE_FAST 1 (b) # 1 2 - [3]
12 STORE_FAST 2 (c) # 1 2 3 []
5 15 LOAD_FAST 2 (c) # 1 2 3 [3]
18 LOAD_FAST 1 (b) # 1 2 3 [3, 2]
21 LOAD_FAST 0 (a) # 1 2 3 [3, 2, 1]
24 BUILD_TUPLE 3 # 1 2 3 [(3, 2, 1)]
27 DUP_TOP # 1 2 3 [(3, 2, 1), (3, 2, 1)]
28 UNPACK_SEQUENCE 3 # 1 2 3 [3, 2, 1, (3, 2, 1)]
31 STORE_FAST 0 (a) # 3 2 3 [2, 1, (3, 2, 1)]
34 STORE_FAST 1 (b) # 3 2 3 [1, (3, 2, 1)]
37 STORE_FAST 2 (c) # 3 2 1 [(3, 2, 1)]
40 DUP_TOP # 3 2 1 [(3, 2, 1), (3, 2, 1)]
41 UNPACK_SEQUENCE 3 # 3 2 1 [3, 2, 1, (3, 2, 1)]
44 STORE_FAST 2 (c) # 3 2 3 [2, 1, (3, 2, 1)]
47 STORE_FAST 0 (a) # 2 2 3 [1, (3, 2, 1)]
50 STORE_FAST 1 (b) # 2 1 3 [(3, 2, 1)]
53 UNPACK_SEQUENCE 3 # 2 1 3 [3, 2, 1]
56 STORE_FAST 1 (b) # 2 3 3 [2, 1]
59 STORE_FAST 0 (a) # 2 3 3 [1]
62 STORE_FAST 2 (c) # 2 3 1 []
Upvotes: 1
Reputation: 26886
a, b, c = 1, 2, 3
b, a, c = c, b, a
print(a, b, c)
# 2, 3, 1
c, a, b = b, a, c
print(a, b, c)
# 2, 1, 3
a, b, c = c, a, b
print(a, b, c)
# 3, 2, 1
a, b, c = 1, 2, 3
# a, b, c = c, a, b = b, a, c = c, b, a
temp = c, b, a
a, b, c = temp
print(a, b, c)
# 3 2 1
c, a, b = temp
print(a, b, c)
# 2 1 3
b, a, c = temp
print(a, b, c)
# 2 3 1
Basically: the loading happen from the right according to c, b, a
, while the storing happen from left to right.
This is evidenced by disassembling the expression:
import dis
def chained_assign():
a, b, c = 1, 2, 3
a, b, c = c, a, b = b, a, c = c, b, a
return a, b, c
dis.dis(chained_assign)
Output:
5 0 LOAD_CONST 4 ((1, 2, 3))
2 UNPACK_SEQUENCE 3
4 STORE_FAST 0 (a)
6 STORE_FAST 1 (b)
8 STORE_FAST 2 (c)
6 10 LOAD_FAST 2 (c)
12 LOAD_FAST 1 (b)
14 LOAD_FAST 0 (a)
16 BUILD_TUPLE 3
18 DUP_TOP
20 UNPACK_SEQUENCE 3
22 STORE_FAST 0 (a)
24 STORE_FAST 1 (b)
26 STORE_FAST 2 (c)
28 DUP_TOP
30 UNPACK_SEQUENCE 3
32 STORE_FAST 2 (c)
34 STORE_FAST 0 (a)
36 STORE_FAST 1 (b)
38 UNPACK_SEQUENCE 3
40 STORE_FAST 1 (b)
42 STORE_FAST 0 (a)
44 STORE_FAST 2 (c)
7 46 LOAD_FAST 0 (a)
48 LOAD_FAST 1 (b)
50 LOAD_FAST 2 (c)
52 BUILD_TUPLE 3
54 RETURN_VALUE
Notice the order of the STORE_FAST
and LOAD_FAST
instructions from line 6.
Additional discussion here:
Upvotes: 4
Reputation: 841
It is because, when you write like this it means -: a = c = b = c value of a becomes c, the value of c becomes b and the value of b becomes c. so in last the change in the variable is taking place for b not a.
so the output would be-:
2 3 1
not-:
3 2 1
Upvotes: 1