Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python a,b = b,a implementation? How is it different from C++ swap function?

I met this problem when I want to try a python version of: https://leetcode.com/problems/first-missing-positive/discuss/17071/My-short-c++-solution-O(1)-space-and-O(n)-time

I am not sure why a[0], a[a[0]] = a[a[0]], a[0] this one does not do the swap?

>>> nums
[2, 1, 0]
>>> a = [2,1,0]
>>> a[0], a[a[0]] = a[a[0]], a[0]
>>> a
[2, 1, 0]
>>> a[0]
2
>>> a[0],a[2] = a[2], a[0]
>>> a
[0, 1, 2]

My guess is that the implementation of a, b = b, a syntax is something like:

tmp = a[0] (tmp = 2)
a[0]  = a[a[0]] (a[0] = a[2] = 0)
a[a[0]] = tmp (a[a[0]] = a[0] = tmp = 2)

Then I checked the implementation of swap function in C++. I know nothing about C++, but it looks like the idea is the same : http://www.cplusplus.com/reference/algorithm/swap/

The behavior of these function templates is equivalent to:
template <class T> void swap (T& a, T& b)
{
  T c(std::move(a)); a=std::move(b); b=std::move(c);
}
template <class T, size_t N> void swap (T (&a)[N], T (&b)[N])
{
  for (size_t i = 0; i<N; ++i) swap (a[i],b[i]);
}

we have c = a, then a = b and b = a So why C++ swap function does not have this problem? And how to write this kind of swap function in a pythonic way?

like image 551
RioAraki Avatar asked Aug 21 '18 13:08

RioAraki


People also ask

What is swap function Python?

Python: swapping two variables Swapping two variables refers to mutually exchanging the values of the variables. Generally, this is done with the data in memory. The simplest method to swap two variables is to use a third temporary variable : define swap(a, b) temp := a a := b b := temp.

How is swap function implemented?

swap() function in C++ Here is the syntax of swap() in C++ language, void swap(int variable_name1, int variable_name2); If we assign the values to variables or pass user-defined values, it will swap the values of variables but the value of variables will remain same at the actual place.

How many types of swaps are there in Python?

Python3. Method 4: Using arithmetic operators we can perform swapping in two ways.

What is the use of swap function in C?

It swaps the values of two integer variables. For example, swap(x, y); will swap the values of variables x and y.


2 Answers

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]
  1. a[a[0]] takes the value from the a[0] element (equal to 2) of the list a (value 0).
  2. a[0] is 2 hence the tuple created is (0,2)
  3. Tuple (0,2) is unpacked and 0 replaces 2 in the list (0th element).
  4. Now, a[a[0]] can be read as: take 0th element of list a (which is currently 0) and then replace the value in the list at that place with 2 from tuple unpacking (now 0 is replaced by 2 - 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.

like image 112
sophros Avatar answered Oct 20 '22 06:10

sophros


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

like image 6
argo Avatar answered Oct 20 '22 05:10

argo