python a,b = b,a implementation? How is it different from C++ swap function?
To understand this you need to go inside the implementation using dis
.
First lets consider a simple swap function:
from dis import dis
def swap(i, j):
i, j = j, i
dis(swap)
Output Byte Code:
4 0 LOAD_FAST 1 (j)
2 LOAD_FAST 0 (i)
4 ROT_TWO
6 STORE_FAST 0 (i)
8 STORE_FAST 1 (j)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
You can see that there is ROT_TWO which means that
Swaps the two top-most stack items.
This ROT_TWO
is mainly responsible for the swapping.
Now coming to your question:
Lets take the example which is working:
from dis import dis
def swap():
a = [2, 1]
a[0], a[1] = a[1], a[0]
dis(swap)
Output Byte Code :
4 0 LOAD_CONST 1 (2)
2 LOAD_CONST 2 (1)
4 BUILD_LIST 2
6 STORE_FAST 0 (a)
5 8 LOAD_FAST 0 (a)
10 LOAD_CONST 2 (1)
12 BINARY_SUBSCR
14 LOAD_FAST 0 (a)
16 LOAD_CONST 3 (0)
18 BINARY_SUBSCR
20 ROT_TWO
22 LOAD_FAST 0 (a)
24 LOAD_CONST 3 (0)
26 STORE_SUBSCR
28 LOAD_FAST 0 (a)
30 LOAD_CONST 2 (1)
32 STORE_SUBSCR
34 LOAD_CONST 0 (None)
36 RETURN_VALUE
Output byte code is similar to what we have when it is a simple swap function.
But when the code is changed:
from dis import dis
def swap():
a = [1, 0]
a[0], a[a[0]] = a[a[0]], a[0]
dis(swap)
swap()
Output is
4 0 LOAD_CONST 1 (1)
2 LOAD_CONST 2 (0)
4 BUILD_LIST 2
6 STORE_FAST 0 (a)
5 8 LOAD_FAST 0 (a)
10 LOAD_FAST 0 (a)
12 LOAD_CONST 2 (0)
14 BINARY_SUBSCR
16 BINARY_SUBSCR
18 LOAD_FAST 0 (a)
20 LOAD_CONST 2 (0)
22 BINARY_SUBSCR
24 ROT_TWO
26 LOAD_FAST 0 (a)
28 LOAD_CONST 2 (0)
30 STORE_SUBSCR
32 LOAD_FAST 0 (a)
34 LOAD_FAST 0 (a)
36 LOAD_CONST 2 (0)
38 BINARY_SUBSCR
40 STORE_SUBSCR
42 LOAD_CONST 0 (None)
44 RETURN_VALUE
You can see the output byte code that top two items are the same. Hence it doesn't swap
This kind of the behaviour is indeed related to the way Python evaluates the expression of the type
a,b=b,a
In fact, what Python does is first it "prepares" the values of the right side by creating a tuple (b,a)
. Then this tuple is unpacked and assigned to the variables in the reverse order.
It is important to note that although Python uses references to objects the objects the variable names refer to may change if they refer to values of immutable type. It is not so with mutable types (illustrated by example in Python FAQ).
To break down the example with mutable types (lists) that you used:
a = [2,1,0]
a[0], a[a[0]] = a[a[0]], a[0]
a[a[0]]
takes the value from thea[0]
element (equal to2
) of the lista
(value0
).a[0]
is2
hence the tuple created is(0,2)
- Tuple
(0,2)
is unpacked and0
replaces2
in the list (0th element). - Now,
a[a[0]]
can be read as: take 0th element of lista
(which is currently0
) and then replace the value in the list at that place with2
from tuple unpacking (now0
is replaced by2
- which make the operation look like it does nothing to the list).
As suggested in the answer from von Oak
changing the order helps because the step from the point 4. above does not replace the value again.
I suggest you refer to passing by assignment answer to understand functions and parameter passing.