详解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 25 Python
python选择排序算法实例总结
Jul 01 Python
Python中str is not callable问题详解及解决办法
Feb 10 Python
python 创建弹出式菜单的实现代码
Jul 11 Python
利用标准库fractions模块让Python支持分数类型的方法详解
Aug 11 Python
Python3.6安装及引入Requests库的实现方法
Jan 24 Python
python爬虫之自动登录与验证码识别
Jun 15 Python
深入浅析Python 中的sklearn模型选择
Oct 12 Python
python温度转换华氏温度实现代码
Dec 06 Python
Python datetime模块的使用示例
Feb 02 Python
python爬虫破解字体加密案例详解
Mar 02 Python
Python爬虫之爬取某文库文档数据
Apr 21 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中截取中文字符串的代码小结
2011/07/17 PHP
深入解析PHP内存管理之谁动了我的内存
2013/06/20 PHP
php的hash算法介绍
2014/02/13 PHP
PHP封装的完整分页类示例
2018/08/21 PHP
客户端 使用XML DOM加载json数据的方法
2010/09/28 Javascript
用jquery与css打造个性化的单选框和复选框
2010/10/20 Javascript
js arguments,jcallee caller用法总结
2013/11/30 Javascript
javascript校验价格合法性实例(必须输入2位小数)
2014/05/05 Javascript
jQuery实现响应浏览器缩放大小并改变背景颜色
2014/10/31 Javascript
jQuery中clearQueue()方法用法实例
2014/12/29 Javascript
jQuery实现的Div窗口震动效果实例
2015/08/07 Javascript
JavaScript检测并限制复选框选中个数的方法
2015/08/12 Javascript
深入剖析javascript中的exec与match方法
2016/05/18 Javascript
JS 清除字符串数组中,重复元素的实现方法
2016/05/24 Javascript
深入浅析Vue组件开发
2016/11/25 Javascript
JavaScript的事件机制详解
2017/01/17 Javascript
详解axios在node.js中的post使用
2017/04/27 Javascript
Angular 4.x+Ionic3踩坑之Ionic3.x pop反向传值详解
2018/03/13 Javascript
微信小程序实现点击卡片 翻转效果
2019/09/04 Javascript
vue-preview动态获取图片宽高并增加旋转功能的实现
2020/07/29 Javascript
vue自定义指令和动态路由实现权限控制
2020/08/28 Javascript
[43:43]完美世界DOTA2联赛PWL S2 FTD.C vs Rebirth 第一场 11.22
2020/11/24 DOTA
pycham查看程序执行的时间方法
2018/11/29 Python
python模拟登陆,用session维持回话的实例
2018/12/27 Python
使用python telnetlib批量备份交换机配置的方法
2019/07/25 Python
python 比较2张图片的相似度的方法示例
2019/12/18 Python
Python守护进程实现过程详解
2020/02/10 Python
Pycharm无法打开双击没反应的问题及解决方案
2020/08/17 Python
如何使用Python进行PDF图片识别OCR
2021/01/22 Python
写clone()方法时,通常都有一行代码,是什么?
2012/10/31 面试题
工商技校毕业生自荐信
2013/11/15 职场文书
心碎乌托邦的创业计划书范文
2013/12/26 职场文书
小组口号大全
2014/06/09 职场文书
财产保全担保书
2015/01/20 职场文书
小学生暑假安全保证书
2015/07/13 职场文书
css实现两栏布局,左侧固定宽,右侧自适应的多种方法
2021/08/07 HTML / CSS