视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Python使用dis模块把Python反编译为字节码的用法详解
2020-11-27 14:29:22 责编:小采
文档


dis — Disassembler for Python bytecode,即把python代码反汇编为字节码指令.
使用超级简单:

python -m dis xxx.py

Python 代码是先被编译为字节码后,再由Python虚拟机来执行字节码, Python的字节码是一种类似汇编指令的中间语言, 一个Python语句会对应若干字节码指令,虚拟机一条一条执行字节码指令, 从而完成程序执行。
Python dis 模块支持对Python代码进行反汇编, 生成字节码指令。
当我在网上看到while 1比while True快的时候,我感到很困惑,为何会有这种区别呢?
于是使用dis来深入.
假设est_while.py代码如下.

#coding=utf-8 
while 1: 
 pass 
 
while True: 
 pass 

下面是使用dis来进行剖析.

E:>python -m dis test_while.py 
 2 0 SETUP_LOOP 3 (to 6) 
 
 3 >> 3 JUMP_ABSOLUTE 3 
 
 5 >> 6 SETUP_LOOP 10 (to 19) 
 >> 9 LOAD_NAME 0 (True) 
 12 POP_JUMP_IF_FALSE 18 

可以看到,在while 1这里(第3行),直接是JUMP_ABSOLUTE指令;
而while True这里(第5行),由LOAD_NAME和POP_JUMP_IF_FALSE指令组成.
原来True在python2中不是一个关键字,只是一个内置的变量,bool类型,值为1,即True+True输出2.
而且还可以被赋值.比如赋值True = 2, 甚至可以赋值True = False.
所以while True的时候, 每次循环都要检查True的值, 对应指令LOAD_NAME.
这就是为什么while True比while 1慢了.
不过在python3中,True变成了关键字了.while 1和while True的指令相同,所以没有性能区别了.

再来看个小例子,先来一小段代码:

In[6]: def test(): 
... x = 1 
... if x < 3: 
... return "yes" 
... else: 
... return "no" 

代码执行后会输出:

In[7]: import dis 
In[8]: dis.dis(test) 
 2 0 LOAD_CONST 1 (1) 
 3 STORE_FAST 0 (x) 
 
 3 6 LOAD_FAST 0 (x) 
 9 LOAD_CONST 2 (3) 
 12 COMPARE_OP 0 (<) 
 15 POP_JUMP_IF_FALSE 22 
 
 4 18 LOAD_CONST 3 ('yes') 
 21 RETURN_VALUE 
 
 6 >> 22 LOAD_CONST 4 ('no') 
 25 RETURN_VALUE 
 26 LOAD_CONST 0 (None) 
 29 RETURN_VALUE 

以第一条指令为例, 第一列的数字(2)表示对应源代码的行数。第二列的数字是字节码的索引,指令LOAD_CONST在0位置。第三列是指令本身对应的人类可读的名字。第四列表示指令的参数。第5列则是计算后的实际参数。其中的“>>" 表示跳转的目标, 第4列的“22” 表明了跳转到索引为22的指令。Python代码在编译过程中会生成CodeObject, CodeObject是在虚拟机中的抽象表示, 在Python C源码中表示为PyCodeObject, 而生成的.pyc 文件则是字节码在磁盘中的表现形式。
以Python代码为讲,test.__code__.co_code 表示test函数的字节码指令序列。
将此序列打印出来,

code = [ord(i) for i in list(test.__code__.co_code)] 
print code 

输出:

代码如下:

[100, 1, 0, 125, 0, 0, 124, 0, 0, 100, 2, 0, 107, 0, 0, 114, 22, 0, 100, 3, 0, 83, 100, 4, 0, 83, 100, 0, 0, 83]

对照dis输出的字节码指令, 以[100,1,0]序列为例。100表示在Python字节码定义中的索引,在python代码中,
可以通过dis.opname[100]查看,即为LOAD_CONST。而后的两个字节表示指令的参数。而dis输出的字节码指令中,
第二列的字节码索引则是指当前指令在co_code序列中所在的位置。
dis输出的字节码指令中,部分指令是没有参数, 在co_code 中也同样可以看到,83(RETURN_VALUE)直接接上下一条指令100(LOAD_CONST)。

下载本文
显示全文
专题