元组 (a,b)=(b,a) 中的成员交换如何在内部工作? [英] How does swapping of members in tuples (a,b)=(b,a) work internally?

查看:23
本文介绍了元组 (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 值的交换如何在内部进行?它绝对没有使用临时变量.

How does this swapping of values of a and b work internally? Its definitely not using a temp variable.

推荐答案

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

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.

对于 2 或 3 项的元组赋值,Python 直接使用栈:

For tuple assignments with 2 or 3 items, Python just uses the stack directly:

>>> 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 opcode 交换前两个位置在堆栈上,所以堆栈现在在顶部有 [b, a] .这两个 STORE_FAST 操作码 然后采用这两个值并将它们存储在赋值左侧的名称中.第一个 STORE_FAST 弹出堆栈顶部的值并将其放入 a,下一个再次弹出,将值存储在 b 中.需要旋转是因为 Python 保证左侧目标列表中的分配是从左到右完成的.

After the two LOAD_FAST opcodes (which push a value from a variable onto the stack), the top of stack holds [a, b]. The ROT_TWO opcode swaps the top two positions on the stack so the stack now has [b, a] at the top. The two STORE_FAST opcodes then takes those two values and store them in the names on the left-hand side of the assignment. The first STORE_FAST pops a value of the top of the stack and puts it into a, the next pops again, storing the value in b. The rotation is needed because Python guarantees that assignments in a target list on the left-hand side are done from left to right.

对于 3 名分配,ROT_THREE<执行/a> 后跟 ROT_TWO 以反转堆栈上的前三项.

For a 3-name assignment, ROT_THREE followed by ROT_TWO is executed to reverse the top three items on the stack.

对于较长的左侧赋值,会构建一个显式元组:

For longer left-hand-side assignments, an explicit tuple is built:

>>> 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 操作.

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 then UNPACK_SEQUENCE pops the tuple from the stack again, pushes all elements back from the tuple back onto the stack again for the STORE_FAST operations.

后者可能看起来是一种浪费的操作,但赋值的右侧可能是完全不同的东西,一个产生元组的函数调用,所以 Python 解释器不做任何假设并始终使用 UNPACK_SEQUENCE 操作码.即使对于两个和三个名称分配操作,它也是如此,但稍后(窥视孔)优化步骤BUILD_TUPLE/UNPACK_SEQUENCE 组合替换为具有上述 ROT_TWO 的 2 或 3 个参数,并且ROT_THREE 操作码提高效率.

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 a BUILD_TUPLE / UNPACK_SEQUENCE combination with 2 or 3 arguments with the above ROT_TWO and ROT_THREE opcodes for efficiency.

这篇关于元组 (a,b)=(b,a) 中的成员交换如何在内部工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆