2018-06-12 Python里的数值交换

曾经被问到 “Python里 a, b = b, a” 是怎么实现的?

准备工作

在回答这个问题之前,先介绍一个库 - dis。使用这个库,可以更清楚地看到Python是如何实现数值交换的。

dis.dis([bytesource])
Disassemble the bytesource object. 
bytesource can denote either a module, a class, a method, a function, or a code object.
For a module, it disassembles all functions.
For a class, it disassembles all methods.
For a single code sequence, it prints one line per bytecode instruction. 
If no object is provided, it disassembles the last traceback.

也就是对一个模块、类、方法、函数、代码对象进行反编译。

a, b = b, a

>>> def f(a, b):
...     a, b = b, a
...
>>> import dis
>>> dis.dis(f)
  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
  1. LOAD_FAST,把右边的b入栈
  2. LOAD_FAST,把右边的a入栈
  3. ROT_TWO,把栈顶的两个元素交换,即b在栈顶,a在第二个位置
  4. STORE_FAST,把栈顶元素赋值给a(即把b给a)
  5. STORE_FAST,把栈顶元素赋值给b(即把a给b)
    至此,实现了数值交换。

a, b, c = b, c, a

上面介绍的是两个数值的交换,那么三个数值是如何交换的呢?

>>> def f(a, b, c):
...     a, b, c = b, c, a
...
>>> dis.dis(f)
  2           0 LOAD_FAST                1 (b)
              3 LOAD_FAST                2 (c)
              6 LOAD_FAST                0 (a)
              9 ROT_THREE
             10 ROT_TWO
             11 STORE_FAST               0 (a)
             14 STORE_FAST               1 (b)
             17 STORE_FAST               2 (c)
             20 LOAD_CONST               0 (None)
             23 RETURN_VALUE

这里多了一个 ROT_THREE,它的意思是把栈顶元素放到第三个位置,然后原先的第二、第三位置的元素上移。
栈的情况如下:

栈顶
bca

ROT_THREE之后:

栈顶
abc

ROT_TWO之后:

栈顶
acb

然后出栈、赋值即可实现数值交换。
那么还有没有 ROT_FOUR 和 ROT_FIVE 呢?
答案是没有了!更多的数值交换下面即将介绍。

更多变量的数值交换,以及给多变量赋值

>>> def f(a,b,c,d):
...     a,b,c,d = b,c,d,a
...
>>> dis.dis(f)
  2           0 LOAD_FAST                1 (b)
              3 LOAD_FAST                2 (c)
              6 LOAD_FAST                3 (d)
              9 LOAD_FAST                0 (a)
             12 BUILD_TUPLE              4
             15 UNPACK_SEQUENCE          4
             18 STORE_FAST               0 (a)
             21 STORE_FAST               1 (b)
             24 STORE_FAST               2 (c)
             27 STORE_FAST               3 (d)
             30 LOAD_CONST               0 (None)
             33 RETURN_VALUE
>>> def f(a, b, c, d):
...     a, b, c, d = [1,2,3,4]
...
>>> dis.dis(f)
  2           0 LOAD_CONST               1 (1)
              3 LOAD_CONST               2 (2)
              6 LOAD_CONST               3 (3)
              9 LOAD_CONST               4 (4)
             12 BUILD_LIST               4
             15 UNPACK_SEQUENCE          4
             18 STORE_FAST               0 (a)
             21 STORE_FAST               1 (b)
             24 STORE_FAST               2 (c)
             27 STORE_FAST               3 (d)
             30 LOAD_CONST               0 (None)
             33 RETURN_VALUE
>>> def f(a,b,c,d):
...     a,b,c,d = (1,2,3,4)
...
>>> dis.dis(f)
  2           0 LOAD_CONST               5 ((1, 2, 3, 4))
              3 UNPACK_SEQUENCE          4
              6 STORE_FAST               0 (a)
              9 STORE_FAST               1 (b)
             12 STORE_FAST               2 (c)
             15 STORE_FAST               3 (d)
             18 LOAD_CONST               0 (None)
             21 RETURN_VALUE
>>> def f(a,b,c,d):
...     a,b,c,d = 1,2,3,4
...
>>> dis.dis(f)
  2           0 LOAD_CONST               5 ((1, 2, 3, 4))
              3 UNPACK_SEQUENCE          4
              6 STORE_FAST               0 (a)
              9 STORE_FAST               1 (b)
             12 STORE_FAST               2 (c)
             15 STORE_FAST               3 (d)
             18 LOAD_CONST               0 (None)
             21 RETURN_VALUE

其中UNPACK_SEQUENCE的意思是把栈顶的多个元素打开成独立的值,从右向左摆放(也就是 reverse 一下)

Unpacks TOS into count individual values, which are put onto the stack right-to-left.
TOS => top of stack

总结

  1. Python为了实现数值交换的特性,特地实现了两个方法:ROT_TWO和ROT_THREE。
  2. dis这个库可以很好地帮助我们去看清Python的内部实现,从而能够更深入地了解Pythonic,以及用更加Pythonic的方式去编程。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值