Jaccorot 日事日毕日清日高

ARTS-008

2020-07-17

一、Algorithm

二、Review

三、Tip

a,b=b,a 剖析

Python 的交换变量操作不完全基于解包操作,有时候是,有时候不是!

  • Python 能在一条语句中实现多重赋值,这是利用了序列解包的特性

  • Python 能在一条语句中实现变量交换,不需引入中间变量,在变量数少于 4 个时(3.8 版本起是少于 5 个),CPython 是利用了 ROT_* 指令来交换栈中的元素,当变量数超出时,则是利用了序列解包的特性。

  • 序列解包是 Python 的一大特性,但是在本文的例子中,CPython 解释器在小小的操作中还提供了几个优化的指令,这绝对会超出大多数人的认知

  1. a,b = 1,2
  • 第一步 LOAD_CONST 把“=”号右侧的两个数字作为元组放到栈中
  • 第二步 UNPACK_SEQUENCE 是序列解包,接着把解包结果写入局部作用域的变量上。 two
    1. a,b = b,a

参照上图

  • 两个 LOAD_FAST 是从局部作用域中读取变量的引用,并存入栈中,
  • 接着是最关键的 ROT_TWO 操作,它会交换两个变量的引用值,
  • 然后两个 STORE_FAST 是将栈中的变量写入局部作用域中。 ROT_TWO 指令是 CPython 解释器实现的对于栈顶两个元素的快捷操作,改变它们指向的引用对象。ROT_THREE 和 ROT_FOUR,分别是快捷交换三和四个变量(摘自:ceval.c 文件,ROT_FOUR是3.8新加入)
  1. a,b,c,d = d,c,b,a 同2

  2. a,b,c,d,e = e,d,c,b,a five BUILD_TUPLE 指令会将给定数量的栈顶元素创建成元组,然后被 UNPACK_SEQUENCE 指令解包,再依次赋值.

值得一提的是,此处之所以比前面的“a,b=1,2”多出一个 build 操作,是因为每个变量的 LOAD_FAST 需要先单独入栈,无法直接被组合成 LOAD_CONST 入栈。也就是说,“=”号右侧有变量时,不会出现前文中的 LOAD_CONST 一个元组的情况。

  1. a,b = b, 1 several 赋值语句中有变量, 且 a,b 共两个变量, 则使用ROT_TWO 那几个指令是跟栈中元素的数量有关,而不是跟赋值语句中实际交换的变量数有关.

[https://mp.weixin.qq.com/s/VN8g_wfcWgN5um1G_-Oaw](https://mp.weixin.qq.com/s/VN8g_wfcWgN5um1G-_Oaw)

四、Share


Similar Posts

上一篇 ARTS-007

下一篇 ARTS-009