交换两个变量的值,大家最常见的写法是这样的:

>>> temp = x

>>> x = y

>>> y = temp

但其实更 Pythonic 的写法是这样的:

>>> x, y = y, x

大家有没有想过为什么在 Python 中可以这样交换两个变量的值?

Python 代码是先解释(这里的解释是相对编译而言的,Python 不同与 C/C++ 之类的编译型语言,是需要从源文件编译成机器指令)成 Python 字节码(byte code, .pyc文件主要是用来存储这些字节码的)之后,再由 Python 解释器来执行这些字节码的。一般来说,Python 语句会对应若干字节码指令,Python 的字节码类似于汇编指令的中间语言,但是一个字节码并不只是对应一个机器指定。

内置模块 dis 可以用来分析字节码。DOC

The dis module supports the analysis of CPython bytecode by disassembling it. The CPython bytecode which this module takes as an input is defined in the file Include/opcode.h and used by the compiler and the interpreter.

常用的 dis 模块方法: dis.dis([bytesource])

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.

dis.dis 接收参数为一个代码块(可以是模块,类,方法,函数,或者是对象),可以得到这个代码块对应的字节码指令序列。

>>> import dis

>>> def test():

... a = 1

...

...

>>> dis.dis(test)

3 0 LOAD_CONST 1 (1)

3 STORE_FAST 0 (a)

6 LOAD_CONST 0 (None)

9 RETURN_VALUE

输出的格式分别是:行号,地址,指令,操作参数, 参数解释(识别变量名称,常量值等)

切入正题, 我们直接来看下第二种写法的字节码指令:

swap_2.py

x = 1

y = 3

x, y = y, x

python -m dis swap_2.py

1 0 LOAD_CONST 0 (1)

3 STORE_NAME 0 (x)

2 6 LOAD_CONST 1 (3)

9 STORE_NAME 1 (y)

3 12 LOAD_NAME 1 (y)

15 LOAD_NAME 0 (x)

18 ROT_TWO

19 STORE_NAME 0 (x)

22 STORE_NAME 1 (y)

25 LOAD_CONST 2 (None)

28 RETURN_VALUE

部分字节码指令如下,具体的指令请移步官网:

LOAD_CONST(consti)

Pushes co_consts[consti] onto the stack.

STORE_NAME(namei)

Implements name = TOS. namei is the index of name in the attribute co_names of the code object. The compiler tries to use STORE_FAST or STORE_GLOBAL if possible.

LOAD_NAME(namei)

Pushes the value associated with co_names[namei] onto the stack.

ROT_TWO()

Swaps the two top-most stack items.

解释下上面的字节码指令:

第一行执行两个字节码指令, 分别是LOAD_CONST 和 STORE_NAME,执行的动作是将 co_consts[0] 压栈(也就是常量表的第一个常量,整数1压入栈中),然后获取co_names[0]的变量名x(变量名表的第一个名字),栈顶元素(整数1)出栈和co_names[0]存储到f->f_locals。

第二行的执行方式如同第一行。

co_consts[0] = 1

co_names[0] = x

f->f_locals['x'] = 1

co_consts[1] = 3

co_names[1] = y

f->f_locals['y'] = 3

重点在第三行,前两行的计算顺序都是从友往左进行的(一般情况下, Python 表达式的计算顺序是从左到右,但是在表达式赋值的时候,表达式右边的操作数优先于左边),也就是说,第四行是这样执行的,先创建元组(y, x),执行的动作是两个 LOAD_NAME,会依次搜索local,global,builtin名字空间中的co_names[1](对应变量名y)和co_names[0](对应变量名x)并把相对应的值压栈。接下去执行的动作是交换ROT_TWO, 交换栈顶的两个元素位置。

从下一个执行指令就可以看出来,先获取co_names[0]的变量名x,栈顶元素(现在是原先y的值)出栈并储存,两次存储就实现了交换两个变量的值。

第二种方法不借助任何中间变量并且能够获得更好的性能。我们可以简单测试下:

>>> from timeit import Timer

>>> Timer('temp = x;x = y;y = temp', 'x=2;y=3').timeit()

0.030814170837402344

>>> Timer('x, y = y, x', 'x=2;y=3').timeit()

0.027340173721313477

为什么第二种方法消耗的时间更少呢?可以猜测一下,是中间变量赋值引起的耗时。具体验证可以分析下两种方法的字节码指令。

Life such short,be Pythonic .

Blog : JunNplus

python中x、y=y、x_浅谈 (x, y) = (y, x)相关推荐

  1. python中zip的使用_浅谈Python中的zip()与*zip()函数详解

    前言 1.实验环境: Python 3.6: 2.示例代码地址:下载示例: 3.本文中元素是指列表.元组.字典等集合类数据类型中的下一级项目(可能是单个元素或嵌套列表). zip(*iterables ...

  2. python中 是什么类型_浅谈python中的变量默认是什么类型

    浅谈python中的变量默认是什么类型 1.type(变量名),输出的结果就是变量的类型: 例如 >>> type(6) 2.在Python里面变量在声明时,不需要指定变量的类型,变 ...

  3. python中判断列表数据类型_浅谈Python数据类型判断及列表脚本操作

    数据类型判断 在python(版本3.0以上)使用变量,并进行值比较时.有时候会出现以下错误: TypeError: unorderable types: NoneType() < int() ...

  4. python中怎么调用函数_浅谈Python中函数的定义及其调用方法

    一.函数的定义及其应用 所谓函数,就是把具有独立功能的代码块组织成为一个小模块,在需要的时候调用函数的使用包含两个步骤 1.定义函数–封装独立的功能 2.调用函数–享受封装的成果 函数的作用:在开发时 ...

  5. python中dtype什么意思_浅谈python 中的 type(), dtype(), astype()的区别

    如下所示: 函数 说明 type() 返回数据结构类型(list.dict.numpy.ndarray 等) dtype() 返回数据元素的数据类型(int.float等) 备注:1)由于 list. ...

  6. python中zip什么意思_浅谈Python中的zip()与*zip()函数详解 python的zip函数加上一个*号,是什么含义...

    python 当中的zip( )函数到底是干嘛的?你越来越善解人意,就没人在意你的委屈和脾气. zip([1,2,3],['a','b','c']) 结果是 [(1, 'a'), (2, 'b'), ...

  7. python中image什么意思_浅谈python图片处理Image和skimage的区别

    做cnn的难免要做大量的图片处理.由于接手项目时间不长,且是新项目,前段时间写代码都很赶,现在稍微总结(恩,总结是个好习惯). 1,首先安装python-Image和python-skimage.py ...

  8. Python中的“鸭子形态”,浅谈一下

    一.鸭子形态来源 首先在初接触Python就应该知道的,Python是弱类型编程语言 因此,Python中不支持多态,也用不到多态,多态的概念是应⽤于java和C#这些强类型语⾔中的,但是Python ...

  9. python类中方法的执行顺序-浅谈Python的方法解析顺序(MRO)

    方法解析顺序, Method Resolution Order 从一段代码开始 考虑下面的情况: class A(object): def foo(self): print('A.foo()') cl ...

最新文章

  1. 郁闷的时候看看这头驴,改变你的心态!
  2. 3.1线性判别函数【模式识别】
  3. Scrapy实战篇(一)之爬取链家网成交房源数据(上)
  4. tipi 深入理解php内核 pdf_大牛的学习笔记-深入理解Linux内核(完整版)
  5. 动态规划——命运(hdu2571)
  6. JAVA中运用数组的四种排序方法
  7. 2008.05.21 下午茶in萨贝尔
  8. 枚举算法:完美综合式
  9. 4.2 One-Shot 学习
  10. API 接口设计中 Token 类型的分类与设计
  11. 区别js中的3/2(结果1.5))与 java 中的 2/3(结果:0)
  12. 米尔电子zynq ultrascale+ mpsoc底板外设资源清单分享
  13. Java元组类型之javatuples
  14. Leetcode 刷题笔记(二十二) ——贪心算法篇之进阶题目
  15. 十分钟走进大数据世界
  16. hadoop ha环境下的datanode启动报错java.lang.NumberFormatException: For input string: 10m
  17. 大数据领域一些值得读的论文(不断更新
  18. 使用Swift模拟Window-LFU
  19. Apache APISIX 社区成员助力 openEuler 发布第一个社区创新版
  20. Ant Design Vue全局对话确认框(confirm)的回调不触发

热门文章

  1. Golang相关面试题
  2. 【virtualbox】虚拟机virtualbox mac版使用教程
  3. double和Double区别
  4. 【PWA】响应式开发
  5. OID科普:OID为什么被称为元标识?
  6. 提取图片中的文字怎么做?这几种简单方法别错过
  7. 大四实习两个月的体会
  8. php仿糗事百科,thinkphp精仿糗事百科整站源码
  9. 第九届蓝桥杯单片机省赛题目解析
  10. 【真的】git pull --all 或 git fetch --all取到自己本地所有分支的最新内容