详解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生成器实现微线程编程的教程
Apr 13 Python
Python中使用bidict模块双向字典结构的奇技淫巧
Jul 12 Python
Python实现ssh批量登录并执行命令
Oct 25 Python
python 递归遍历文件夹,并打印满足条件的文件路径实例
Aug 30 Python
tensorflow: 查看 tensor详细数值方法
Jun 13 Python
Python读取英文文件并记录每个单词出现次数后降序输出示例
Jun 28 Python
Python实现曲线拟合操作示例【基于numpy,scipy,matplotlib库】
Jul 12 Python
Flask和Django框架中自定义模型类的表名、父类相关问题分析
Jul 19 Python
python实现翻转棋游戏(othello)
Jul 29 Python
Python中bisect的使用方法
Dec 31 Python
Python CSS选择器爬取京东网商品信息过程解析
Jun 01 Python
Opencv+Python识别PCB板图片的步骤
Jan 07 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
用Flash图形化数据(二)
2006/10/09 PHP
Http 1.1 Etag 与 Last-Modified提高php效率
2008/01/10 PHP
Discuz Uchome ajaxpost小技巧
2011/01/04 PHP
巧用php中的array_filter()函数去掉多维空值的代码分享
2012/09/07 PHP
php基于curl重写file_get_contents函数实例
2016/11/08 PHP
php魔法函数与魔法常量使用介绍
2017/07/23 PHP
PHP cURL获取微信公众号access_token的实例
2018/04/28 PHP
yii2实现Ueditor百度编辑器的示例代码
2018/11/02 PHP
EASYUI TREEGRID异步加载数据实现方法
2012/08/22 Javascript
jQuery+CSS 半开折叠效果原理及代码(自写)
2013/03/04 Javascript
如何使用jQuery Draggable和Droppable实现拖拽功能
2013/07/05 Javascript
JavaScript中操作字符串小结
2015/05/04 Javascript
使用jQuery Mobile框架开发移动端Web App的入门教程
2016/05/17 Javascript
基于JS代码实现实时显示系统时间
2016/06/16 Javascript
基于angular中的重要指令详解($eval,$parse和$compile)
2016/10/21 Javascript
jquery html5 视频播放控制代码
2016/11/06 Javascript
js实现图片360度旋转
2017/01/22 Javascript
VueJS组件之间通过props交互及验证的方式
2017/09/04 Javascript
vue.js-div滚动条隐藏但有滚动效果的实现方法
2018/03/03 Javascript
vue-cli3访问public文件夹静态资源报错的解决方式
2020/09/02 Javascript
vue3+typeScript穿梭框的实现示例
2020/12/29 Vue.js
Python实现的线性回归算法示例【附csv文件下载】
2018/12/29 Python
Python变量类型知识点总结
2019/02/18 Python
通过python检测字符串的字母
2020/02/18 Python
Links of London官方网站:英国标志性的珠宝品牌
2017/04/09 全球购物
经济信息管理专业大学生求职信
2013/09/27 职场文书
生物技术专业求职信
2014/06/10 职场文书
捐资助学感谢信
2015/01/21 职场文书
2015年党风廉政承诺书
2015/01/22 职场文书
2016年大学自主招生自荐信范文
2015/03/24 职场文书
拾金不昧表扬信怎么写
2015/05/04 职场文书
违反纪律检讨书范文
2015/05/07 职场文书
银行岗位培训心得体会
2016/01/09 职场文书
2016年综治和平安建设宣传月活动总结
2016/04/01 职场文书
教你如何用Python实现人脸识别(含源代码)
2021/06/23 Python
HTML基础详解(上)
2021/10/16 HTML / CSS