Python 为什么只需一条语句“a,b=b,a”,就能直接交换两个变量?
The following article is from Python猫 Author 豌豆花下猫
IT服务圈儿
有温度、有态度的IT自媒体平台
来源:Python猫(ID:python_cat)
>>> print(x, y) # 结果:1 2
x = 1,2
,然后打印出 x,或者在“=”号右侧写成一个元组,就能证实到这一点:>>> print(x) # 结果:(1, 2)
>>> x, y = (1, 2)
>>> print(x, y) # 结果:1 2
>>> x, y = y, x
>>> print(x, y) # 结果:2 1
dis
大杀器看看编译的字节码:上图开了两个窗口,可以方便比较“a,b=b,a”与“a,b=1,2”的不同:“a,b=b,a”操作:两个 LOAD_FAST 是从局部作用域中读取变量的引用,并存入栈中,接着是最关键的 ROT_TWO 操作,它会交换两个变量的引用值,然后两个 STORE_FAST 是将栈中的变量写入局部作用域中。
“a,b=1,2”操作:第一步 LOAD_CONST 把“=”号右侧的两个数字作为元组放到栈中,第二步 UNPACK_SEQUENCE 是序列解包,接着把解包结果写入局部作用域的变量上。
CPython 应该是以为这几种变量的交换操作很常见,因此才提供了专门的优化指令。就像 [-5,256] 这些小整数被预先放到了整数池里一样。对于更多变量的交换操作,实际上则会用到前面说的解包操作:截图中的 BUILD_TUPLE 指令会将给定数量的栈顶元素创建成元组,然后被 UNPACK_SEQUENCE 指令解包,再依次赋值。值得一提的是,此处之所以比前面的“a,b=1,2”多出一个 build 操作,是因为每个变量的 LOAD_FAST 需要先单独入栈,无法直接被组合成 LOAD_CONST 入栈。也就是说,“=”号右侧有变量时,不会出现前文中的 LOAD_CONST 一个元组的情况。最后还有一个值得一提的细节,那几个指令是跟栈中元素的数量有关,而不是跟赋值语句中实际交换的变量数有关。看一个例子就明白了:分析至此,你应该明白前文中的结论是怎么回事了吧?我们稍微总结一下:ROT_TWO
Swaps the two top-most stack items. ROT_THREE
Lifts second and third stack item one position up, moves top down to position three. ROT_FOUR
Lifts second, third and forth stack items one position up, moves top down to position four.
New in version 3.8.
Python 能在一条语句中实现多重赋值,这是利用了序列解包的特性
Python 能在一条语句中实现变量交换,不需引入中间变量,在变量数少于 4 个时(3.8 版本起是少于 5 个),CPython 是利用了 ROT_* 指令来交换栈中的元素,当变量数超出时,则是利用了序列解包的特性。
序列解包是 Python 的一大特性,但是在本文的例子中,CPython 解释器在小小的操作中还提供了几个优化的指令,这绝对会超出大多数人的认知
*版权声明:转载文章和图片均来自公开网络,版权归作者本人所有,推送文章除非无法确认,我们都会注明作者和来源。如果出处有误或侵犯到原作者权益,请与我们联系删除或授权事宜。