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

栈顶
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的方式去编程。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容

  • Java byte code 的学习意义 为啥要学java bytecode,这就跟你问我已经会python了为...
    shanggl阅读 1,660评论 0 3
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  • 〇、前言 本文共108张图,流量党请慎重! 历时1个半月,我把自己学习Python基础知识的框架详细梳理了一遍。 ...
    Raxxie阅读 18,948评论 17 410
  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,783评论 0 38
  • 我们三年前在厦门的时候特别穷。 穷到什么程度呢? 有一天我跟小黄豆坐在黄厝附近的沙滩上,有两个和尚打扮的中年人走过...
    酹韶阅读 286评论 0 3