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:

>>> x, y = 1.2
>>> print(x, y)  # Result: 1, 2
Copy 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)  # Result: 1, 2
Copy 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) # Result: 2 1
Copy 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

If you think this analysis is good, you will enjoy these articles:

1. Why does Python use indentation to divide code blocks?

2. Is Python’s indentation anti-human?

3. Why does Python use semicolons as statement terminators?

4. Why does Python have a main function? Why don’t I recommend main?

5. Why does Python recommend serpentine nomenclature?

6. Why doesn’t Python support the i++ increment syntax and the ++ operator?

Last: This article is part of the “Why Python” series, which focuses on the syntax, design, and development of Python. The series tries to show the charm of Python by asking “why” questions. Some topics will be launched video version, please watch in B station, watch the address: video address

Python cat is a series of articles, including why Python series, Cat philosophy series, Python Advanced series, good books recommended series, technical writing, quality English recommendation and translation, and so on.