Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does swapping of members in tuples (a,b)=(b,a) work internally?

In [55]: a = 5

In [56]: b = 6

In [57]: (a, b) = (b, a)

In [58]: a
Out[58]: 6

In [59]: b
Out[59]: 5

How does this swapping of values of a and b work internally? Its definitely not using a temp variable.

like image 508
praveen Avatar asked Jan 10 '14 15:01

praveen


People also ask

How does swapping works in Python?

In short, the expression: “ a, b = b, a”, first right gets assigned to first left and second right get assigned to second left at the same time therefore swap values of a and b.

Can we swap elements in tuple?

Tuples, like strings, are immutable: it is not possible to assign to the individual items of a tuple.

What happens when you add two tuples?

Append an item to tuple tuple is immutable, but you can concatenate multiple tuples with the + operator. At this time, the original object remains unchanged, and a new object is generated. Only tuples can be concatenated. It cannot be concatenated with other types such as list .


1 Answers

Python separates the right-hand side expression from the left-hand side assignment. First the right-hand side is evaluated, and the result is stored on the stack, and then the left-hand side names are assigned using opcodes that take values from the stack again.

For tuple assignments with 2 or 3 items, Python just uses the stack directly:

>>> import dis
>>> def foo(a, b):
...     a, b = b, a
... 
>>> dis.dis(foo)
  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        

After the two LOAD_FAST opcodes (which push a value from a variable onto the stack), the top of stack holds [a, b]. The ROT_TWO opcode swaps the top two positions on the stack so the stack now has [b, a] at the top. The two STORE_FAST opcodes then takes those two values and store them in the names on the left-hand side of the assignment. The first STORE_FAST pops a value of the top of the stack and puts it into a, the next pops again, storing the value in b. The rotation is needed because Python guarantees that assignments in a target list on the left-hand side are done from left to right.

For a 3-name assignment, ROT_THREE followed by ROT_TWO is executed to reverse the top three items on the stack.

For longer left-hand-side assignments, an explicit tuple is built:

>>> def bar(a, b, c, d):
...     d, c, b, a = a, b, c, d
... 
>>> dis.dis(bar)
  2           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 LOAD_FAST                2 (c)
              9 LOAD_FAST                3 (d)
             12 BUILD_TUPLE              4
             15 UNPACK_SEQUENCE          4
             18 STORE_FAST               3 (d)
             21 STORE_FAST               2 (c)
             24 STORE_FAST               1 (b)
             27 STORE_FAST               0 (a)
             30 LOAD_CONST               0 (None)
             33 RETURN_VALUE        

Here the stack with [d, c, b, a] is used to build a tuple (in reverse order, BUILD_TUPLE pops from the stack again, pushing the resulting tuple onto the stack), and then UNPACK_SEQUENCE pops the tuple from the stack again, pushes all elements back from the tuple back onto the stack again for the STORE_FAST operations.

The latter may seem like a wasteful operation, but the right-hand side of an assignment may be something entirely different, a function call that produces a tuple perhaps, so the Python interpreter makes no assumptions and uses the UNPACK_SEQUENCE opcode always. It does so even for the two and three-name assignment operations, but a later (peephole) optimization step replaces a BUILD_TUPLE / UNPACK_SEQUENCE combination with 2 or 3 arguments with the above ROT_TWO and ROT_THREE opcodes for efficiency.

like image 172
Martijn Pieters Avatar answered Oct 17 '22 11:10

Martijn Pieters