The text and pictures in this article come from the network, only for learning, exchange, do not have any commercial purposes, copyright belongs to the original author, if you have any questions, please contact us to deal with

Author: Python Cat source: Tencent Cloud

The original link: cloud.tencent.com/developer/a…

From the time I started working with Python, I found Python’s tuple unpacking very interesting, very neat and easy to use.

The most obvious example is multiple assignment, which assigns values to multiple variables simultaneously in a single statement:

Print (x, y) print(x, y) print(x, yCopy the code

In this case, the two numbers to the right of the assignment operator “=” are stored in a tuple, which becomes (1,2), and then unpacked, assigning successively to the two variables to the left of “=”.

We can verify this if we simply write x = 1,2 and print x, or write a tuple to the right of the “=” sign:

> > > x = 1, 2 > > > print # (x) results: (1, 2) > > > x, y = (1, 2) > > > print (x, y) # results: 1. 2Copy the code

Some blogs or public posts introduce this feature by following the example of swapping values of two variables directly:

> > > x, y = 1, 2 > > > x, y = y, x > > > print (x, y) # results: 2 to 1Copy the code

In general, swapping two variables requires the introduction of a third variable. The simple truth is that if you want to exchange two cups of water, you will naturally need a third container.

However, Python is written without the use of intermediate variables, which take the form of unpack assignment above. Because of this similarity, many people mistakenly assume that Python’s variable exchange operations are also based on unpacking.

But is this the case?

I did some research and found that some people had tried to answer this question, but their answers were mostly incomplete. (There are plenty of wrong answers, of course, and many more who just know it but never bother to know why.)

Let’s get the answer out of the way: Python swaps are not entirely based on unpacking, sometimes they are, sometimes they aren’t!

Do you find this answer magical? Unheard of? !

What’s going on? To take a look at the two simplest variables in the title, let’s go to dis to see the compiled bytecode:



A,b=b,a “and a,b=1,2”

The “A,b=b,a” operations: the two LOAD_FAST operations read references to variables from the local scope and store them on the stack, followed by the crucial ROT_TWO operation, which swaps references to the two variables, and the two STORE_FAST operations, which write variables from the stack to the local scope. “A,b=1,2” operation: the first step LOAD_CONST puts the two numbers to the right of “=” on the stack as a tuple. The second step UNPACK_SEQUENCE is unpacking the sequence and then writes the unpacking result to the variable in the local scope. It is clear that the two forms that are similar do not actually accomplish the same operation. There is no packing and unpacking step in the operation of exchanging variables!

The ROT_TWO directive is a quick operation implemented by the CPython interpreter on the top two elements of the stack to change the reference objects they point to.

Two other similar instructions are ROT_THREE and ROT_FOUR, which are quick swaps of three and four variables respectively (from the ceval.c file, the latest 3.9 branch) :



Predefined top of the stack operations are as follows:



Check the official documentation for an explanation of these instructions, where ROT_FOUR is new in version 3.8:

ROT_TWO Swaps the two top-most stack items.

ROT_THREE Lifts second and third stack item one position up, moves top

down to position three.

ROT_FOUR Lifts second, third and forth stack items one position up,

moves top down to position four. New in version 3.8.

CPython presumably assumes that these types of variable swaps are common, so it provides specific optimization instructions. It is as if [-5,256] the small integers were pre-placed into the integer pool.

For more variable swaps, the unpacking operations described above are actually used:



The BUILD_TUPLE command in the screenshot creates tuples of a given number of elements at the top of the stack, which are unpacked by the UNPACK_SEQUENCE command and then assigned.

LOAD_FAST (a,b=1,2) LOAD_FAST (b=1,2) LOAD_FAST (b=1,2) LOAD_FAST (b=1,2) LOAD_FAST (b=1,2) LOAD_FAST (b=1,2) LOAD_CONST (b=1,2) LOAD_FAST (b=1,2) LOAD_FAST (b=1,2) LOAD_FAST (b=1,2) That is, LOAD_CONST is not a tuple when there is a variable to the right of the “=” sign.

One last detail worth mentioning is that the instructions are related to the number of elements in the stack, not the actual number of variables exchanged in the assignment statement. Just look at an example:



At this point, you should be able to understand the above conclusion?

Let’s summarize a little bit:

  • Python can implement multiple assignments in a single statement, which takes advantage of sequential unpacking
  • Python can swap variables in a single statement without the need for intermediate variables. CPython uses the ROT_* instruction to swap stack elements when the number of variables is less than four (or less than five starting in 3.8), and makes use of sequence unpacking when the number of variables is greater.
  • Sequence unpacking is a big feature of Python, but in the case of this article, the CPython interpreter provides several optimized instructions for small operations that are definitely beyond most people’s awareness