Python 中如何实现交换变量?

How swapping variables is implemented in Python?

下面的代码在 Python 中如何工作:

a = input()
b = input()
a, b = b, a  # STATEMENT 1
print(a, b)

语句 1 是否在 Python 堆内存 space 中创建了第三个变量来交换两个数字,或者它是否使用某种算法来进行交换?

这是一个简单的字节码操作,不需要任何中间变量来进行交换。请参阅此演示:

import dis

code = '''
a = input()
b = input()
a, b = b, a
'''

dis.dis(code)

Output:

 2           0 LOAD_NAME                0 (input)
             2 CALL_FUNCTION            0
             4 STORE_NAME               1 (a)

 3           6 LOAD_NAME                0 (input)
             8 CALL_FUNCTION            0
            10 STORE_NAME               2 (b)

 4          12 LOAD_NAME                2 (b)
            14 LOAD_NAME                1 (a)
            16 ROT_TWO
            18 STORE_NAME               1 (a)
            20 STORE_NAME               2 (b)
            22 LOAD_CONST               0 (None)
            24 RETURN_VALUE

注:与字节码整体一样,这当然只是CPython的一个实现细节。

在提供 python 代码的翻译字节码方面做得很好。

我在这里复制以供参考:

Python代码:

a = input()
b = input()
a, b = b, a  # STATEMENT 1
print(a, b)

字节码:

 2           0 LOAD_NAME                0 (input)
             2 CALL_FUNCTION            0
             4 STORE_NAME               1 (a)

 3           6 LOAD_NAME                0 (input)
             8 CALL_FUNCTION            0
            10 STORE_NAME               2 (b)

 4          12 LOAD_NAME                2 (b)
            14 LOAD_NAME                1 (a)
            16 ROT_TWO                  # swapping done here
            18 STORE_NAME               1 (a)
            20 STORE_NAME               2 (b)
            22 LOAD_CONST               0 (None)
            24 RETURN_VALUE

ROT_TWO 操作交换 python 堆栈的前 2 个值。那么到目前为止我们实际上有什么:

Python swaps the 2 values by calling a swap (ROT_TWO) subroutine.

如果这是您想要达到的程度并且它回答了您的问题,那很好。 然而,对于那些想要更深入了解此交换 (ROT_TWO) 子例程如何工作的人,here is the official CPython implementation:

#define TOP()             (stack_pointer[-1])
#define SECOND()          (stack_pointer[-2])
#define SET_TOP(v)        (stack_pointer[-1] = (v))
#define SET_SECOND(v)     (stack_pointer[-2] = (v))
/*..*/
case TARGET(ROT_TWO): {
   PyObject *top = TOP();
   PyObject *second = SECOND();
   SET_TOP(second);
   SET_SECOND(top);
   FAST_DISPATCH();
}

或者换句话说 ROT_TWO 的实现实际上执行了以下步骤(ab 是堆栈的前 2 个值):

x1 = a
x2 = b
a = x2
b = x1

因此实现使用了辅助临时位置x1x2),实际上它使用了 2 个辅助内存位置而不是最小的 1 个辅助位置交换两个值的位置,一个内存效率更高的实现会做:

x = a
a = b
b = x

在当前的计算模型下,swapping two values can be done only in so many different ways并不会神奇地发生:

  1. 使用辅助临时存储
  2. 采用一系列 XOR(或类似的算术)运算

所以总而言之,Python在幕后确实使用辅助临时位置来交换两个值。