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.
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.
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:
After the two
LOAD_FAST
opcodes (which push a value from a variable onto the stack), the top of stack holds[a, b]
. TheROT_TWO
opcode swaps the top two positions on the stack so the stack now has[b, a]
at the top. The twoSTORE_FAST
opcodes then takes those two values and store them in the names on the left-hand side of the assignment. The firstSTORE_FAST
pops a value of the top of the stack and puts it intoa
, the next pops again, storing the value inb
. 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 byROT_TWO
is executed to reverse the top three items on the stack.For longer left-hand-side assignments, an explicit tuple is built:
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 thenUNPACK_SEQUENCE
pops the tuple from the stack again, pushes all elements back from the tuple back onto the stack again for theSTORE_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 aBUILD_TUPLE
/UNPACK_SEQUENCE
combination with 2 or 3 arguments with the aboveROT_TWO
andROT_THREE
opcodes for efficiency.