上次写到,Python 的执行方式是把代码编译成bytecode(字节码)指令,然后由虚拟机来执行这些 bytecode

而 bytecode 长成这个样子:  b'|\x00\x00d\x01\x00\x14S' 。显然这个样子适合机器看,不适合人类看。

虽然你可以通过查字典的方式,手动把这段 bytecode 编写成人类可以看得懂的样子,

但是这么劳累的事情,为什么要自己亲手来做呢,让你的男仆机器来做不就好了吗。

Python 的反汇编工具 dis 就可以办到这件事。下面用绚丽的紫色来对dis.dis 的输出结果进行分列解释。

>>> def double(a):
return a*2 # 并不知道为什么贴在这里缩进会是这样 >>> import dis
>>> dis.dis(double)
2 0 LOAD_FAST 0 (a)
3 LOAD_CONST 1 (2)
6 BINARY_MULTIPLY
7 RETURN_VALUE

上一篇文章的末尾已经解释过了,第2列的数字 0 3 6 7 是 bytecode 的偏移量。

第3列很好理解,都是opcode。注意这些 opcode 是给弱弱的人类看的,不是给机器看的,机器只要看b'|\x00\x00d\x01\x00\x14S' 这种东西就行了),

比如第一个opcode, 大名叫做叫LOAD_FAST,查一下资料,发现它的意思是 Pushes a reference to the local co_varnames[var_num] onto the stack.

中文意思:把本地某个东西的引用压到栈里。

什么东西呢?那就是 co_varnames[var_num] 啦。

(内心OS: 看这形象似乎是列表或者字典,字符串不太可能,自定义对象更不可能……)

>>> double.__code__.co_varnames[0] # 第4列里的下标 0
'a'
>>> double.__code__.co_consts[1] # 第4列里的下标 1
2

上次讲过了:double 是函数对象 function object

double.__code__是这个函数对象的代码对象 code object

看看返回值,a 和2, 也就是第5列

那么第1列的2是什么?看起来好像很神秘的样子,其实不过是源代码中的行号。本例中表示是在double 代码的第2行。

上次详细解释过,b'|\x00\x00d\x01\x00\x14S' 其实是8个整数

>>> double.__code__.co_code
b'|\x00\x00d\x01\x00\x14S'
>>> for i in double.__code__.co_code:
print (i, end=" ") 124 0 0 100 1 0 20 83

通过查字典或者另一个更加巧妙正常的办法,你可以找出124代表的opcode是 LOAD_FAST,  100代表 LOAD_CONST

这类opcode 后面各带两个字节的参数,分别是0  0   和 1  0

但有些opcode后面是没有参数的,比如 83 代表的 RETURN_VALUE

不了解的人可能会觉得有点奇怪,为什么RETURN_VALUE不带参数呢,不带参数怎么返回结果呢?

查一查资料,RETURN_VALUE的意思是 Returns with TOS to the caller of the function. 即把TOS返回给这个函数的调用者。TOS= top of stack, 。咱出栈了。

现在问题来了:为什么要与字节码 bytecode 玩耍? 直接写Python代码方便多了,为什么要去写字节码?

因为可以节省编译时间,这里有一篇非常详细的文章,作者在遗传编程领域工作,发现他们Python 程序的总运算时间中,有50%都被编译过程吃掉。于是作者深入到 bytecode 层次进行了小小改动,大幅削减了编译时间,把总的运算时间降至不足原先的一半。

可惜没有找到这篇文章的中文翻译。不知道有没有人肯出钱让我翻译。

文中写道:

bytecode 写好之后,我们必须让Python 明白它要执行这些bytecode。这时就需要创建一个完整的 code object。

bytecode 是 code object 的主要成分,但是还需要其他东西才能构成完整的 code object。就像鸡丁是宫保鸡丁中的主要食材,但它也不能没有花生。

这个过程中要用到types.CodeType()

有了code object 之后,接下来可以调用Types.FunctionType,利用这些代码创建一个函数对象( function object)。

上一篇写了怎么抽丝剥茧,顺着function object 找 code object,再找 bytecode,这里就完全倒过来,添枝加叶,逆流而上了。

理解 Python 的执行方式,与字节码 bytecode 玩耍 (下)的更多相关文章

  1. 理解 Python 的执行方式,与字节码 bytecode 玩耍 (上)

    这里有个博客讲 Python 内部机制,已经有一些中文翻译. 可能因为我用的Python 3.5,例子跑起来有些不一样. 此外,我又查了其他一些参考资料,总结如下: Python 的执行方式 先看一个 ...

  2. 任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行

    任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行 多线程 - 廖雪峰的官方网站 https://www.liaoxuefeng ...

  3. 从底层理解Python的执行

    摘要:是否想在Python解释器的内部晃悠一圈?是不是想实现一个Python代码执行的追踪器?没有基础?不要怕,这篇文章让你初窥Python底层的奥妙. [编者按]下面博文将带你创建一个字节码级别的追 ...

  4. Python 字节码bytecode

    字节码bytecode python把源码文件编译成字节码文件,存放在__pycahe子目录内,用.pyc结尾.之后如果不再修改源码文件,运行时则使用*.pyc文件编译成机器码,这样不但运行速度快,而 ...

  5. 深入理解java虚拟机(5)---字节码执行引擎

    字节码是什么东西? 以下是百度的解释: 字节码(Byte-code)是一种包含执行程序.由一序列 op 代码/数据对组成的二进制文件.字节码是一种中间码,它比机器码更抽象. 它经常被看作是包含一个执行 ...

  6. 深入理解JVM虚拟机5:虚拟机字节码执行引擎

    虚拟机字节码执行引擎   转自https://juejin.im/post/5abc97ff518825556a727e66 所谓的「虚拟机字节码执行引擎」其实就是 JVM 根据 Class 文件中给 ...

  7. 深入理解Java虚拟机06--虚拟机字节码执行引擎

    一.前言 物理机的执行引擎是直接在物理硬件如CPU.操作系统.指令集上运行的,但是对于虚拟机来讲,他的执行引擎由自己实现. 执行引擎有统一的外观(Java虚拟机规范),不同类型的虚拟机都遵循了这一规范 ...

  8. JVM学习第三天(JVM的执行子系统)之字节码指令

    早上看了Class类文件结构,晚上继续来看字节码指令,毕竟谁也不是一步登天的(说白了还是穷); 字节码指令 Java虚拟机的指令由一个字节长度的.代表着某种特定操作含义的数字(称为操作码,Opcode ...

  9. python常用执行方式&变量&input函数

    linux系统中执行py文件方式:  ./a.py 需要执行权限 chmod -R 777(最大权限) 常用执行方式: 1. ./a.py2. python a.py 文件内部头加上 #!/usr/b ...

随机推荐

  1. VMware12上安装CentOS7无法上网问题

    常安装使用VMware的搭建集群环境,VMare安装后虚拟机默认的是自动获取IP,有时候用的过程中突然XSHELL中断或者需要固定IP上网,遇到几次居然,但忘了步骤,总结一下,省的每次去找资料 环境配 ...

  2. 微软Office Online服务安装部署(二)

    现在准备配置Client 1.进入到桌面后,打开powershell 输入: Add-WindowsFeature Web-Server,Web-Mgmt-Tools,Web-Mgmt-Console ...

  3. related_name和related_query_name举例区别

    例1: class UserInfo(models.Model): nickname = models.CharField(max_length=32) username = models.CharF ...

  4. Android如何在http头信息里设置参数

    在使用http请求server时常常要传递一些参数给server,如IMEI号.平台号.渠道号.客户端的版本号等一些通用信息,像这些参数我们没有必要每次都拼在url后,我们可以统一添加到http头里. ...

  5. Powershell 脚本判断制定路径下文件是否存在(来源于网络-转载)

    $filelist=gc "file.txt" #获取要检查的文件列表 $csvs= new-object collections.arraylist #创建一个arraylist ...

  6. hugepage优势

    hugepage的优势与使用 +2投票   优势 通过使用hugepage分配可以提高性能,因为需要更少的页,因此需要更少Translation Lookaside Buffers (TLB,高速传送 ...

  7. day 7 编码

    menu = { '北京': { '朝阳': { '国贸': { 'CICC': {}, 'HP': {}, '渣打银行': {} }, '望京': { '陌陌': {}, '奔驰': {} } }, ...

  8. VS 2015 Android 环境设置

    一般有3个地方需要设置(否则新建项目时会弹出值不能为空 null 参数名:path1.参见:http://www.cnblogs.com/fang8206/p/5020942.html) 1.Tool ...

  9. 顺序栈的基本操作(C语言)

    由于现在只学了C语言所以就写这个C语言版的栈的基本操作 这里说一下 :网上和书上都有这种写法 int InitStack(SqStack &p) &p是取地址  但是这种用法好像C并不 ...

  10. PHP幸运大转盘源码,支持ThinkPHP

    原理 先看图 可以看到1-6等奖都只有1个 ,7等奖有6个.指针默认指向上图位置,记为0°. 每个奖项对应不同的角度,圆的角度为360°,分成12块,所以每块为30°. 为了防止指针指着相邻两个将向之 ...