详解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中下划线的使用方法
Mar 27 Python
python线程池(threadpool)模块使用笔记详解
Nov 17 Python
Python实现PS图像明亮度调整效果示例
Jan 23 Python
python 多维切片之冒号和三个点的用法介绍
Apr 19 Python
Python装饰器原理与简单用法实例分析
Apr 29 Python
python+influxdb+shell编写区域网络状况表
Jul 27 Python
Python从ZabbixAPI获取信息及实现Zabbix-API 监控的方法
Sep 17 Python
对python3.4 字符串转16进制的实例详解
Jun 12 Python
python实现windows倒计时锁屏功能
Jul 30 Python
pycharm配置git(图文教程)
Aug 16 Python
解决python3 安装不了PIL的问题
Aug 16 Python
tensorflow 重置/清除计算图的实现
Jan 19 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
Content-type 的说明
2006/10/09 PHP
PHP4与PHP5的时间格式问题
2008/02/17 PHP
php XPath对XML文件查找及修改实现代码
2011/07/27 PHP
ThinkPHP分组下自定义标签库实例
2014/11/01 PHP
php cli配置文件问题分析
2015/10/15 PHP
使用xampp搭建运行php虚拟主机的详细步骤
2015/10/21 PHP
Linux下编译redis和phpredis的方法
2016/04/07 PHP
不要小看注释掉的JS 引起的安全问题
2008/12/27 Javascript
JQuery jsonp 使用示例代码
2009/08/12 Javascript
jQuery 加上最后自己的验证
2009/11/04 Javascript
jQuery EasyUI API 中文文档 - Pagination分页
2011/09/29 Javascript
JQuery获取浏览器窗口内容部分高度的代码
2012/02/24 Javascript
JavaScript 产生不重复的随机数三种实现思路
2012/12/13 Javascript
js 取时间差去掉周六周日实现代码
2012/12/25 Javascript
Javascript数组操作函数总结
2015/02/05 Javascript
JavaScript使用replace函数替换字符串的方法
2015/04/06 Javascript
JS插件overlib用法实例详解
2015/12/26 Javascript
JavaScript使用forEach()与jQuery使用each遍历数组时return false 的区别
2016/08/26 Javascript
JavaScript实现三级联动菜单实例代码
2017/06/26 Javascript
Babel 入门教程学习笔记
2018/06/13 Javascript
小程序关于请求同步的总结
2019/05/05 Javascript
[04:03]辉夜杯主赛事 12月25日RECAP精彩回顾
2015/12/26 DOTA
[33:42]LGD vs OG 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
[32:36]完美世界DOTA2联赛PWL S3 LBZS vs CPG 第二场 12.12
2020/12/16 DOTA
如何处理Python3.4 使用pymssql 乱码问题
2016/01/08 Python
Python脚本实现12306火车票查询系统
2016/09/30 Python
连接pandas以及数组转pandas的方法
2019/06/28 Python
Python 取numpy数组的某几行某几列方法
2019/10/24 Python
pytorch中使用cuda扩展的实现示例
2020/02/12 Python
萌新HTML5 入门指南(二)
2020/11/09 HTML / CSS
巴西24小时在线药房:Drogasil
2020/06/20 全球购物
辞旧迎新演讲稿
2014/09/15 职场文书
2014财务年度工作总结
2014/11/11 职场文书
领导欢迎词致辞
2015/01/23 职场文书
安全员岗位职责范本
2015/04/11 职场文书
Android开发实现极为简单的QQ登录页面
2022/04/24 Java/Android