详解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多线程爬虫爬取电影天堂资源
Sep 23 Python
Python随机读取文件实现实例
May 25 Python
Python实现公历(阳历)转农历(阴历)的方法示例
Aug 22 Python
matplotlib绘图实例演示标记路径
Jan 23 Python
numpy.random.seed()的使用实例解析
Feb 03 Python
解决nohup执行python程序log文件写入不及时的问题
Jan 14 Python
opencv与numpy的图像基本操作
Mar 08 Python
Python 单例设计模式用法实例分析
Sep 23 Python
pyinstaller还原python代码过程图解
Jan 08 Python
Python基于time模块表示时间常用方法
Jun 18 Python
python实现测试工具(一)——命令行发送get请求
Oct 19 Python
python中复数的共轭复数知识点总结
Dec 06 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
php 遍历数据表数据并列表横向排列的代码
2009/09/05 PHP
Drupal读取Excel并导入数据库实例
2014/03/02 PHP
浅谈PHP中foreach/in_array的使用
2015/11/02 PHP
PHP获取当前文件的父目录方法汇总
2016/07/21 PHP
Yii2中简单的场景使用介绍
2017/06/02 PHP
PHP实现的操作数组类库定义与用法示例
2019/05/24 PHP
php实现简易计算器
2020/08/28 PHP
JavaScript的继承的封装介绍
2013/10/15 Javascript
JavaScript实现当网页加载完成后执行指定函数的方法
2015/03/21 Javascript
javascript运动详解
2015/07/06 Javascript
Bootstrap项目实战之子栏目资讯内容
2016/04/25 Javascript
浅析Javascript中bind()方法的使用与实现
2016/04/29 Javascript
jQuery制作网页版选项卡
2016/07/28 Javascript
用 js 的 selection range 操作选择区域内容和图片
2017/04/18 Javascript
D3.js(v3)+react 实现带坐标与比例尺的柱形图 (V3版本)
2019/05/09 Javascript
在vue中实现清除echarts上次保留的数据(亲测有效)
2020/09/09 Javascript
在vue中使用eslint,配合vscode的操作
2020/11/09 Javascript
用TensorFlow实现lasso回归和岭回归算法的示例
2018/05/02 Python
用于业余项目的8个优秀Python库
2018/09/21 Python
python字典一键多值实例代码分享
2019/06/14 Python
Python 使用 environs 库定义环境变量的方法
2020/02/25 Python
python爬虫泛滥的解决方法详解
2020/11/25 Python
CSS3改变浏览器滚动条样式
2019/01/04 HTML / CSS
HTML5仿微信聊天界面、微信朋友圈实例代码
2018/01/29 HTML / CSS
美国网上眼镜商城:Zenni Optical
2016/11/20 全球购物
HelloFresh澳大利亚:订购你的美味食品盒、健康餐食
2018/03/28 全球购物
德国黑胶唱片、街头服装及运动鞋网上商店:HHV
2018/08/24 全球购物
C#的几个面试问题
2016/05/22 面试题
老同学聚会感言
2014/02/23 职场文书
青年文明号口号
2014/06/17 职场文书
教师一帮一活动总结
2014/07/08 职场文书
法定授权委托证明书
2014/09/27 职场文书
2015年校务公开工作总结
2015/05/26 职场文书
煤矿安全生产工作总结
2015/08/13 职场文书
财务会计个人原因辞职信
2019/06/21 职场文书
Mysql 一主多从的部署
2022/05/20 MySQL