详解python字节码


Posted in Python onFebruary 07, 2018

Python对不可变序列进行重复拼接操作效率会很低,因为每次都会生成一个新的对象,解释器需要把原来对象中的元素先复制到新的对象里,然后再追加新的元素。

但是CPython对字符串操作进行了优化,因为对字符串做+=操作实在是太普遍了。因此,初始化str时会预留出额外的可扩展空间,从而进行增量操作的时候不会有复制再追加的这个步骤。

通过字节码研究一下这个过程。

>>> s_code = 'a += "b"'
>>> c = compile(s_code, '', 'exec')
>>> c.co_code
b'e\x00\x00d\x00\x007Z\x00\x00d\x01\x00S'
>>> c.co_names
('a',)
>>> c.co_consts
('b', None)

得到的字节码是Bytes类型的。这里穿插一些Bytes类型的知识。

Bytes类型

b'e\x00\x00d\x00\x007Z\x00\x00d\x01\x00S',b表示是Bytes类型。Bytes以二进制字节序列的形式记录数据,每一个字符就代表一个字节(8位)。比如上面的e表示二进制0110 0101。部分ASCII码对照表如下图所示。

但是,不是所有的字节都是可显示的,甚至有些字节无法对应到ASCII码上(因为ASCII码只定义了128个字符,而一个字节有256个)。比如0000 0000对应的ASCII是不可显示的、0111 1111没有对应的ASCII码。

为了表示这些无法显示的字节,就引入了\x符号,其表示后续的字符为16进制。如,\x00表示16进制的00,也就是二进制的0000 0000。

至此,所有字节都可被表示。

字节码分析

回到开始的代码。为了显示方便,将b'e\x00\x00d\x00\x007Z\x00\x00d\x01\x00S'转为16进制来显示。

>>> c.co_code.hex()
'650000640000375a000064010053'

通过opcode.opname函数可以得到操作码所对应的操作指令

>>> import opcode
>>> opcode.opname[0x65]
'LOAD_NAME'

因此,完整的字节码可以解释为(TOS即top-of-stack,栈顶元素):

字节:位置,功能
65:0,LOAD_NAME
0000:参数,将co_names[0]的值,即a的值,压入栈
64:3,LOAD_CONST
0000:参数,将co_consts[0],即'b',压入栈
37:6,INPLACE_ADD,TOS = TOS1 + TOS
5a:7,STORE_NAME
0000:参数,co_names[0]=TOS,即将栈顶赋值给a
64:10,LOAD_CONST
0100:参数
53:13,RETURN_VALUE,Returns with TOS to the caller of the function

实际上借助dis函数可以直接获得可读的字节码:

>>> import dis
>>> dis.dis(s_code)
 1      0 LOAD_NAME        0 (a)
       3 LOAD_CONST        0 ('b')
       6 INPLACE_ADD
       7 STORE_NAME        0 (a)
       10 LOAD_CONST        1 (None)
       13 RETURN_VALUE

完整代码:

s_code = 'a += "b"'
c = compile(s_code, '', 'exec')
c.co_code
c.co_names
c.co_consts
c.co_code.hex()
import dis
dis.dis(s_code)

非常失败,对比了string和tuple的赋值字节码,并没有看出string的优化…

以上就是本次关于python字节码的相关知识点,感谢你对三水点靠木的支持。

Python 相关文章推荐
Python的迭代器和生成器使用实例
Jan 14 Python
在Python的while循环中使用else以及循环嵌套的用法
Oct 14 Python
Python基于正则表达式实现文件内容替换的方法
Aug 30 Python
Python tornado队列示例-一个并发web爬虫代码分享
Jan 09 Python
Python 12306抢火车票脚本 Python京东抢手机脚本
Feb 06 Python
Python 实现交换矩阵的行示例
Jun 26 Python
使用Python求解带约束的最优化问题详解
Feb 11 Python
如何使用repr调试python程序
Feb 28 Python
jupyter notebook实现显示行号
Apr 13 Python
关于tensorflow softmax函数用法解析
Jun 30 Python
python递归函数用法详解
Oct 26 Python
pycharm2021激活码使用教程(永久激活亲测可用)
Mar 30 Python
Tensorflow之构建自己的图片数据集TFrecords的方法
Feb 07 #Python
python深度优先搜索和广度优先搜索
Feb 07 #Python
Python Flask基础教程示例代码
Feb 07 #Python
Python装饰器用法实例总结
Feb 07 #Python
使用apidocJs快速生成在线文档的实例讲解
Feb 07 #Python
Python自定义线程池实现方法分析
Feb 07 #Python
使用apidoc管理RESTful风格Flask项目接口文档方法
Feb 07 #Python
You might like
解析link_mysql的php版
2013/06/30 PHP
微信扫描二维码登录网站代码示例
2013/12/30 PHP
PHP常用的缓存技术汇总
2014/05/05 PHP
在jquery中处理带有命名空间的XML数据
2011/06/13 Javascript
javascript:void(0)是什么意思示例介绍
2013/11/17 Javascript
javascript制作幻灯片(360度全景图片)
2015/07/28 Javascript
js实现简易的单数字随机抽奖(0-9)
2020/03/19 Javascript
全面解析Bootstrap中tooltip、popover的使用方法
2016/06/13 Javascript
微信小程序 页面跳转传参详解
2016/10/28 Javascript
Bootstrap基本插件学习笔记之Alert警告框(20)
2016/12/08 Javascript
使用vue.js实现联动效果的示例代码
2017/01/10 Javascript
使用JS 插件qrcode.js生成二维码功能
2017/02/20 Javascript
angular指令笔记ng-options的使用方法
2017/09/18 Javascript
JavaScript中创建原子的方法总结
2018/08/26 Javascript
JS中min函数实例讲解
2019/02/18 Javascript
Vue form表单动态添加组件实战案例
2019/09/02 Javascript
JQuery使用属性addClass、removeClass和toggleClass实现增加和删除类操作示例
2019/11/18 jQuery
Python求导数的方法
2015/05/09 Python
Django框架下在URLconf中指定视图缓存的方法
2015/07/23 Python
更改Ubuntu默认python版本的两种方法python-> Anaconda
2016/12/18 Python
Python学习笔记之Django创建第一个数据库模型的方法
2019/08/07 Python
浅谈Keras的Sequential与PyTorch的Sequential的区别
2020/06/17 Python
移动端HTML5开发神器之vconsole详解
2020/12/15 HTML / CSS
List, Set, Map是否继承自Collection接口?
2016/05/16 面试题
计算机专业毕业生自我鉴定
2014/01/16 职场文书
20年同学聚会邀请函
2014/02/04 职场文书
出纳试用期自我鉴定
2014/04/07 职场文书
计算机毕业生自荐信
2014/06/12 职场文书
会计专业自荐书
2014/07/08 职场文书
村班子对照检查材料
2014/08/18 职场文书
个人四风对照检查材料
2014/09/26 职场文书
2014年体育教学工作总结
2014/12/09 职场文书
自愿离婚协议书2015
2015/01/26 职场文书
领导视察通讯稿
2015/07/18 职场文书
PHP 对接美团大众点评团购券(门票)的开发步骤
2021/04/03 PHP
用python自动生成日历
2021/04/24 Python