美文网首页
2018-06-12 Python里的数值交换

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

作者: 四火流年 | 来源:发表于2018-06-14 15:04 被阅读83次

曾经被问到 “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,它的意思是把栈顶元素放到第三个位置,然后原先的第二、第三位置的元素上移。
栈的情况如下:

栈顶
b c a

ROT_THREE之后:

栈顶
a b c

ROT_TWO之后:

栈顶
a c b

然后出栈、赋值即可实现数值交换。
那么还有没有 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的方式去编程。

相关文章

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

    曾经被问到 “Python里 a, b = b, a” 是怎么实现的? 准备工作 在回答这个问题之前,先介绍一个库...

  • 数值交换->Swift

    var a = 10binaryPrintIntNumber(num: a)print(a) //交换两个实参的数...

  • C语言,数组

    数组一般操作 数值交换

  • python--数值

    python的数值类型和序列类型 数值类型 python的数值类型有四种,分别是:1.整型 intpytho...

  • 数值交换代码

    方法一 public class Test2 { public static void main(String[]...

  • Python黑帽编程2.2 数值类型

    Python黑帽编程2.2数值类型 数值类型,说白了就是处理各种各样的数字,Python中的数值类型包括整型、长整...

  • Python 介绍

    章节 Python 介绍Python 开发环境搭建Python 语法Python 变量Python 数值类型Pyt...

  • Python3下实现数值交换的几种方式

    使用临时变量 该方法是最简单的,也是最容易理解的,适用于所有编程语言,其实现过程如下: 使用tuple元组 该方法...

  • python 数值

    我只顾着喜欢你,却忘了不合适。 前端QQ群: 981668406在此附上我的QQ: 2489757828 有问题的...

  • 1.2数字

    一、python数值类型基本知识 完整的python数值类型工具包括: 整数和浮点对象 复数对象 小数:固定精度对...

网友评论

      本文标题:2018-06-12 Python里的数值交换

      本文链接:https://www.haomeiwen.com/subject/icwleftx.html