详解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中线程的MQ消息队列实现以及消息队列的优点解析
Jun 29 Python
python交换两个变量的值方法
Jan 12 Python
使用python读取.text文件特定行的数据方法
Jan 28 Python
PyQt5 QTable插入图片并动态更新的实例
Jun 18 Python
使用python 写一个静态服务(实战)
Jun 28 Python
详解python解压压缩包的五种方法
Jul 05 Python
python django中8000端口被占用的解决
Dec 17 Python
python GUI库图形界面开发之PyQt5动态加载QSS样式文件
Feb 25 Python
Python selenium模块实现定位过程解析
Jul 09 Python
Python try except finally资源回收的实现
Jan 25 Python
matplotlib 范围选区(SpanSelector)的使用
Feb 24 Python
python3 删除所有自定义变量的操作
Apr 08 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
为什么《星际争霸》是测试人工智能的理想战场
2019/12/03 星际争霸
php操作xml
2013/10/27 PHP
PHP清除字符串中所有无用标签的方法
2014/12/01 PHP
Laravel框架路由管理简单示例
2019/05/07 PHP
Laravel框架创建路由的方法详解
2019/09/04 PHP
php快速导入大量数据的实例方法
2019/09/23 PHP
ajax提交表单实现网页无刷新注册示例
2014/05/08 Javascript
js创建一个input数组并绑定click事件的方法
2014/06/12 Javascript
基于jQuery插件实现环形图标菜单旋转切换特效
2015/05/15 Javascript
jQuery多级手风琴菜单实例讲解
2015/10/22 Javascript
微信小程序页面开发注意事项整理
2017/05/18 Javascript
Node.js  事件循环详解及实例
2017/08/06 Javascript
微信小程序 页面跳转事件绑定的实例详解
2017/09/20 Javascript
详解Vue 中 extend 、component 、mixins 、extends 的区别
2017/12/20 Javascript
jQuery进阶实践之利用最优雅的方式如何写ajax请求
2017/12/20 jQuery
Vuex 进阶之模块化组织详解
2018/01/12 Javascript
jQuery实现表单动态添加与删除数据操作示例
2018/07/03 jQuery
对TypeScript库进行单元测试的方法
2019/07/18 Javascript
javascript for循环性能测试示例
2019/08/07 Javascript
微信小程序实现点击空白隐藏的方法示例
2019/08/13 Javascript
JS 实现发送短信验证码的“59秒后重新发送验证短信”功能
2019/08/23 Javascript
js+canvas实现画板功能
2020/09/13 Javascript
vue自定义树状结构图的实现方法
2020/10/18 Javascript
[38:40]2018DOTA2亚洲邀请赛 4.6淘汰赛 mineski vs LGD 第一场
2018/04/10 DOTA
在Python中操作列表之List.pop()方法的使用
2015/05/21 Python
Python  pip安装lxml出错的问题解决办法
2017/02/10 Python
解决python selenium3启动不了firefox的问题
2018/10/13 Python
Python 的 __str__ 和 __repr__ 方法对比
2020/09/02 Python
澳大利亚便宜隐形眼镜购买网站:QUICKLENS Australia
2018/10/06 全球购物
电子狗项圈:eDog Australia
2019/12/04 全球购物
Java工程师面试集锦之Spring框架
2013/06/16 面试题
别名指示符是什么
2012/10/08 面试题
乡镇党员干部四风对照检查材料思想汇报
2014/09/27 职场文书
安全先进班组材料
2014/12/26 职场文书
Python预测分词的实现
2021/06/18 Python
星际争霸:毕姥爷vs解冻03
2022/04/01 星际争霸