Python使用dis模块把Python反编译为字节码的用法详解
dis—DisassemblerforPythonbytecode,即把python代码反汇编为字节码指令.
使用超级简单:
python-mdisxxx.py
Python代码是先被编译为字节码后,再由Python虚拟机来执行字节码,Python的字节码是一种类似汇编指令的中间语言,一个Python语句会对应若干字节码指令,虚拟机一条一条执行字节码指令,从而完成程序执行。
Pythondis模块支持对Python代码进行反汇编,生成字节码指令。
当我在网上看到while1比whileTrue快的时候,我感到很困惑,为何会有这种区别呢?
于是使用dis来深入.
假设est_while.py代码如下.
#coding=utf-8 while1: pass whileTrue: pass
下面是使用dis来进行剖析.
E:\>python-mdistest_while.py 20SETUP_LOOP3(to6) 3>>3JUMP_ABSOLUTE3 5>>6SETUP_LOOP10(to19) >>9LOAD_NAME0(True) 12POP_JUMP_IF_FALSE18
可以看到,在while1这里(第3行),直接是JUMP_ABSOLUTE指令;
而whileTrue这里(第5行),由LOAD_NAME和POP_JUMP_IF_FALSE指令组成.
原来True在python2中不是一个关键字,只是一个内置的变量,bool类型,值为1,即True+True输出2.
而且还可以被赋值.比如赋值True=2,甚至可以赋值True=False.
所以whileTrue的时候,每次循环都要检查True的值,对应指令LOAD_NAME.
这就是为什么whileTrue比while1慢了.
不过在python3中,True变成了关键字了.while1和whileTrue的指令相同,所以没有性能区别了.
再来看个小例子,先来一小段代码:
In[6]:deftest(): ...x=1 ...ifx<3: ...return"yes" ...else: ...return"no"
代码执行后会输出:
In[7]:importdis In[8]:dis.dis(test) 20LOAD_CONST1(1) 3STORE_FAST0(x) 36LOAD_FAST0(x) 9LOAD_CONST2(3) 12COMPARE_OP0(<) 15POP_JUMP_IF_FALSE22 418LOAD_CONST3('yes') 21RETURN_VALUE 6>>22LOAD_CONST4('no') 25RETURN_VALUE 26LOAD_CONST0(None) 29RETURN_VALUE以第一条指令为例,第一列的数字(2)表示对应源代码的行数。第二列的数字是字节码的索引,指令LOAD_CONST在0位置。第三列是指令本身对应的人类可读的名字。第四列表示指令的参数。第5列则是计算后的实际参数。其中的“>>"表示跳转的目标,第4列的“22”表明了跳转到索引为22的指令。Python代码在编译过程中会生成CodeObject,CodeObject是在虚拟机中的抽象表示,在PythonC源码中表示为PyCodeObject,而生成的.pyc文件则是字节码在磁盘中的表现形式。
以Python代码为讲,test.__code__.co_code表示test函数的字节码指令序列。
将此序列打印出来,
code=[ord(i)foriinlist(test.__code__.co_code)] printcode
输出:
[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]