元组 (a,b)=(b,a) 中成员的交换如何在内部工作? [英] How does swapping of members in tuples (a,b)=(b,a) work internally?
问题描述
在[55]中:a = 5在 [56] 中:b = 6在[57]中:(a, b) = (b, a)在 [58] 中:一个出[58]:6在 [59] 中:b出[59]:5
这种 a 和 b 值的交换在内部是如何工作的?它绝对没有使用临时变量.
Python 将右侧表达式与左侧赋值分开.首先评估右侧,并将结果存储在堆栈中,然后使用操作码分配左侧名称,这些操作码再次来自堆栈中的值.
对于 2 或 3 项的元组赋值,Python 只是直接使用堆栈:
<预><代码>>>>导入文件>>>def foo(a, b):... a, b = b, a...>>>dis.dis(foo)2 0 LOAD_FAST 1 (b)3 LOAD_FAST 0 (a)6 ROT_TWO7 STORE_FAST 0 (a)10 STORE_FAST 1 (b)13 LOAD_CONST 0 (无)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 415 解包_序列 418 STORE_FAST 3 (d)21 STORE_FAST 2 (c)24 STORE_FAST 1 (b)27 STORE_FAST 0 (一)30 LOAD_CONST 0(无)33 RETURN_VALUE这里用[d, c, b, a]
的栈来构建元组(以相反的顺序,BUILD_TUPLE
再次从堆栈中弹出,将生成的元组推入堆栈),然后 UNPACK_SEQUENCE
再次从堆栈中弹出元组,将所有元素推回元组再次返回堆栈以进行 STORE_FAST
操作.
后者似乎是一种浪费的操作,但赋值的右侧可能完全不同,一个函数调用可能产生一个元组,所以 Python 解释器不做任何假设并始终使用 UNPACK_SEQUENCE
操作码.它甚至对于两个和三个名称赋值操作也是如此,但是后来的(窥视孔)优化步骤用上述 ROT_TWO
和 2 或 3 个参数替换了 BUILD_TUPLE
/UNPACK_SEQUENCE
组合和ROT_THREE
操作码以提高效率.
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
How does this swapping of values of a and b work internally? Its definitely not using a temp variable.
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.
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
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.
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
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.
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屋!