用dis分析python的bytecode

一篇介绍性的文章:PyMOTW: dis – Python Bytecode Disassembler
python库dis的document:dis — Disassembler for Python bytecode,这里可以找到所有指令的含义。

.py文件如果是通过模块导入的话,为了加速,解释器一般会生成一个.pyc的二进制文件,他们就是CPython的bytecode,算是一种中间语言(就像java的字节码一样)。
所有的.py文件只要通过

python -m dis xxx.py

就可以输出有可读性的bytecode,其实就是对它将要生成的.pyc作了一次翻译。这条指令中-m参数使用来调用python模块直接当脚本执行的,可以直接在代码中调用dis.dis的函数,效果一样。

这个东西很好玩,比如:

a = 3
c = 2 if a == 1 else 3
print c
d = a == 1 and 2 or 3
print d

编译结果为:

  1           0 LOAD_CONST               0 (3)
              3 STORE_NAME               0 (a)

  3           6 LOAD_NAME                0 (a)
              9 LOAD_CONST               1 (1)
             12 COMPARE_OP               2 (==)
             15 POP_JUMP_IF_FALSE       24
             18 LOAD_CONST               2 (2)
             21 JUMP_FORWARD             3 (to 27)
        >>   24 LOAD_CONST               0 (3)
        >>   27 STORE_NAME               1 (c)

  4          30 LOAD_NAME                1 (c)
             33 PRINT_ITEM          
             34 PRINT_NEWLINE       

  6          35 LOAD_NAME                0 (a)
             38 LOAD_CONST               1 (1)
             41 COMPARE_OP               2 (==)
             44 POP_JUMP_IF_FALSE       53
             47 LOAD_CONST               2 (2)
             50 JUMP_IF_TRUE_OR_POP     56
        >>   53 LOAD_CONST               0 (3)
        >>   56 STORE_NAME               2 (d)

  7          59 LOAD_NAME                2 (d)
             62 PRINT_ITEM          
             63 PRINT_NEWLINE       
             64 LOAD_CONST               3 (None)
             67 RETURN_VALUE 

很容易解答之前的一个问题,if-else语法和and-or语法这两个小tricks是否效果一样。答案很明显了。

还有很多很有意思的地方,比如你可以用这个验证一个pythoner必知必会的循环效率问题:

i = 0
while i < 10:
    i += 1
    pass

for i in range(10):
    pass

bytecode太长不贴了,总之可以很清晰的观察出来循环体的指令数有很大差别。

在比如这个问题:

a = 0
b = 0
a = a + 1
b += 1

他们的指令只相差一句话。

还有一些有意思的真相,可以试试:

a = [2*i for i in range(10)]

b = []
for i in range(10):
    b.append(2*i)

直接的列表生成器在指令数量上是有优势的。

虽然python程序的性能其实并不能完全从这个看出来,但是借用一个成语就是「可见一斑」了。
总之这里面可以看出python代码规范的一些缘由。

话说我为什么研究起了这个,因为我不小心入了坑选了科创3-G(貌似是这个名字,赵海老师的),做和编译相关的工作。我提交了计划书,我说我写一个python bytecode的反编译器…所以这篇文章算是我整个工作的第一步。剩下的工作还是比较明确的,就是Github上面找个现成的看懂了重写一遍,当然我决定如果我找到C的版本,我就用python重写,反之亦然(Wow, so clever!…Oh, shit!)…

Tags :

3 thoughts on “用dis分析python的bytecode”

发表评论

电子邮件地址不会被公开。 必填项已用*标注

Click the right image To submit your comment: