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
请问这个交换内部的价值观和b的工作? 它绝对不使用临时变量。
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
请问这个交换内部的价值观和b的工作? 它绝对不使用临时变量。
蟒分离从左手侧分配的右手边的表达。 第一右手侧进行评价,并且结果被存储在堆栈上,然后将左侧的名称使用的是再次采取值从堆栈操作码赋值。
对于具有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
操作码始终。 它这样做,即使是二,三名赋值操作, 但是稍后的(窥视孔)优化步骤代替了BUILD_TUPLE
/ UNPACK_SEQUENCE
有2个或3个参数与上述组合ROT_TWO
和ROT_THREE
操作码效率。