Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

a,b = b,a in python vs std::swap() in C++

Tags:

c++

python

I know that a,b = b,a is basically assigning a tuple (a,b) the values of another tuple (b,a). This is, essentially, swapping the values form a to b and from b to a. Thus, causing a "swap".

This is the functionality of the swap() function in C++.

From research, I have seen that C++'s swap() function uses a third temporary variable to perform the swap. I haven't been able to find how is a,b = b,a implemented in python.

How is a,b = b,a implemented?

Does python also use a third temporary variable? If it doesn't, how does it work?

How do both operations compare in terms of speed? I'm guessing that if python also uses a third variable, the difference in execution time would be due to python being interpreted.

Edit: All answers are great, but the community seems to think that Sapan's is the best one. Also thanks to a_guest, whom, although didn't post an answer, gave us a great deal of information in the comments. Also: everyone seems to agree that swap() is faster just because its C++. I don't necessarily agree with that. Python can be very fast if run as a frozen binary.

like image 366
Fabián Montero Avatar asked Aug 24 '18 07:08

Fabián Montero


People also ask

What does std :: swap do in C++?

swap() in C++ The function std::swap() is a built-in function in the C++ Standard Template Library (STL) which swaps the value of two variables. Parameters: The function accepts two mandatory parameters a and b which are to be swapped. The parameters can be of any data type.

Does swap function work in C?

To answer your question directly, no there is no swap function in standard C, although it would be trivial to write.

Is there a swap in Python?

A simple swap function in Python is generally considered a function that takes two initialized variables, a = val_a and b = val_b , and returns a result of a = val_b and b = val_a . The function accepts variables of arbitrary types, or more precisely, variables that are assigned with objects of arbitrary types.

How does swap work in Python?

In simple terms, it pushes the values of a and b on the stack, rotates (swaps) the top two elements, then pops the values again.


3 Answers

For tuple assignments, Python uses the stack structure directly:

>>> import dis
>>> def abc(a, b):
...     a, b = b, a
... 
>>> dis.dis(abc)
  2           0 LOAD_FAST                1 (b)
              3 LOAD_FAST                0 (a)
              6 ROT_TWO             
              7 STORE_FAST               0 (a)
             10 STORE_FAST               1 (b)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE  

In python, assignments in a target list on the left-hand side are done from left to right.

like image 133
Sapan Zaveri Avatar answered Oct 18 '22 12:10

Sapan Zaveri


How is a,b = b,a implemented?

First, b, a creates a tuple. You can verify this using e.g.

>>> tmp = 1, 2
>>> tmp
(1, 2)

Then, the assignment uses sequence unpacking, overwriting the names a, b. Hence the code is basically

>>> tmp = (a, b)
>>> b, a = tmp

How do both operations compare in terms of speed?

This would depend on your implementation of python. If you use CPython (the standard version), then C++ would likely be much faster since it is compiled and optimized.

CPython implementation details

In CPython, the swap is sometimes optimized. For small swaps (<4 elements) it uses an optimized swap

>>> def swap(a, b):
>>>     a, b = b, a
>>> dis.dis(swap)
  3           0 LOAD_FAST                1 (b)
              3 LOAD_FAST                0 (a)
              6 ROT_TWO
              7 STORE_FAST               0 (a)
             10 STORE_FAST               1 (b)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE
>>> def swap(a, b, c):
>>>     a, b, c = c, b, a
>>> dis.dis(swap)
  3           0 LOAD_FAST                2 (c)
              3 LOAD_FAST                1 (b)
              6 LOAD_FAST                0 (a)
              9 ROT_THREE
             10 ROT_TWO
             11 STORE_FAST               0 (a)
             14 STORE_FAST               1 (b)
             17 STORE_FAST               2 (c)
             20 LOAD_CONST               0 (None)
             23 RETURN_VALUE

For swaps of 4 or more elements it does exactly what I wrote above, without optimization.

>>> def swap(a, b, c, d):
>>>     a, b, c, d = d, c, b, a
>>> dis.dis(swap)
  3           0 LOAD_FAST                3 (d)
              3 LOAD_FAST                2 (c)
              6 LOAD_FAST                1 (b)
              9 LOAD_FAST                0 (a)
             12 BUILD_TUPLE              4
             15 UNPACK_SEQUENCE          4
             18 STORE_FAST               0 (a)
             21 STORE_FAST               1 (b)
             24 STORE_FAST               2 (c)
             27 STORE_FAST               3 (d)
             30 LOAD_CONST               0 (None)
             33 RETURN_VALUE
like image 36
Jonas Adler Avatar answered Oct 18 '22 13:10

Jonas Adler


Adding to Sapan's answer:

In C++ it might conceptionally use a third variable to swap. But you can see here that the compiler can produce the same assembly as the one shown from python:

void foo(int& a, int& b)
{
    std::swap(a, b);
}

turns into

foo(int&, int&):
    mov     eax, DWORD PTR [rdi]
    mov     edx, DWORD PTR [rsi]
    mov     DWORD PTR [rdi], edx
    mov     DWORD PTR [rsi], eax
    ret

https://godbolt.org/g/dRrzg6

like image 33
Max Langhof Avatar answered Oct 18 '22 12:10

Max Langhof