Python-元组(a,b)=(b,a)中的成员交换在内部如何工作?

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

a和b的值交换在内部如何工作?它绝对不使用临时变量。

回答:

Python将右侧表达式与左侧赋值分开。首先评估右侧,并将结果存储在堆栈中,然后使用再次从堆栈中获取值的操作码分配左侧名称。

对于具有2或3个项目的元组分配,Python只是直接使用堆栈:

>>> 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

在两个LOAD_FAST操作码(将一个变量中的值推入堆栈)之后,堆栈顶部保持[a, b]。该ROT_TWO操作码交换顶部的堆栈上的两个位置,使堆积现在有[b, a]在顶部。然后,这两个STORE_FAST操作码将使用这两个值并将它们存储在分配左侧的名称中。第一个STORE_FAST弹出堆栈顶部的值并将其放入堆栈a,下一个再次弹出,将值存储在中b。需要进行轮换,因为Python保证左侧目标列表中的分配是从左到右完成的。

对于3名分配,执行ROT_THREE后跟ROT_TWO以反转堆栈中的前三项。

对于更长的左侧分配,将建立一个显式元组:

>>> 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

此处的堆栈[d, c, b, a]用于构建元组(以相反的顺序,BUILD_TUPLE再次从堆栈中弹出,将生成的元组推入堆栈中),然后UNPACK_SEQUENCE再次从堆栈中弹出元组,将所有元素从元组推回至再次堆叠以进行STORE_FAST操作。

后者似乎是一个浪费的操作,但是赋值的右侧可能完全不同,一个函数调用可能会生成一个元组,因此Python解释器不做任何假设,而是UNPACK_SEQUENCE始终使用操作码。即使对两个和三个名称的赋值操作也可以这样做,但是稍后的(窥孔)优化步骤使用上面的2或3个自变量替换了BUILD_TUPLE/ UNPACK_SEQUENCE组合,ROT_TWO并提高了ROT_THREE操作码的效率。

以上是 Python-元组(a,b)=(b,a)中的成员交换在内部如何工作? 的全部内容, 来源链接: utcz.com/qa/422049.html

回到顶部