利用dis模块分析python代码

  • 2018-08-07
  • 0
  • 0

python dis模块

作者信息:

Author : 黄志成(小黄)

博客地址: 博客

dis模块通过反汇编来支持CPython 字节码的分析.

下面通过一个例子来说明如何去分析python代码

a = [1, 2]
b = a
a = a + [3, 4]
print(a)
print(b)
a = [1, 2]
b = a
a += [3, 4]
print(a)
print(b)

第一个程序的结果是:

[1, 2, 3, 4]
[1, 2]

第二个程序的结果是:

[1, 2, 3, 4]
[1, 2, 3, 4]

同样是加法运算,但结果却大不同.这是为什么?

这个时候拿出我们的分析神器dis模块。

需要大家通过pip安装.

$ pip install dis

使用方法:

$ python3 -m dis demo1.py

命令行输入这行命令就能对这个文件的python代码进行分析.我们对这两段代码进行分析下

第一段代码分析结果:

  1           0 LOAD_CONST               0 (1)
              2 LOAD_CONST               1 (2)
              4 BUILD_LIST               2
              6 STORE_NAME               0 (a)

  2           8 LOAD_NAME                0 (a)
             10 STORE_NAME               1 (b)

  3          12 LOAD_NAME                0 (a)
             14 LOAD_CONST               2 (3)
             16 LOAD_CONST               3 (4)
             18 BUILD_LIST               2
             20 BINARY_ADD
             22 STORE_NAME               0 (a)

  4          24 LOAD_NAME                2 (print)
             26 LOAD_NAME                0 (a)
             28 CALL_FUNCTION            1
             30 POP_TOP

  5          32 LOAD_NAME                2 (print)
             34 LOAD_NAME                1 (b)
             36 CALL_FUNCTION            1
             38 POP_TOP
             40 LOAD_CONST               4 (None)
             42 RETURN_VALUE

第二段结果分析结果:

  1           0 LOAD_CONST               0 (1)
              2 LOAD_CONST               1 (2)
              4 BUILD_LIST               2
              6 STORE_NAME               0 (a)

  2           8 LOAD_NAME                0 (a)
             10 STORE_NAME               1 (b)

  3          12 LOAD_NAME                0 (a)
             14 LOAD_CONST               2 (3)
             16 LOAD_CONST               3 (4)
             18 BUILD_LIST               2
             20 INPLACE_ADD
             22 STORE_NAME               0 (a)

  4          24 LOAD_NAME                2 (print)
             26 LOAD_NAME                0 (a)
             28 CALL_FUNCTION            1
             30 POP_TOP

  5          32 LOAD_NAME                2 (print)
             34 LOAD_NAME                1 (b)
             36 CALL_FUNCTION            1
             38 POP_TOP
             40 LOAD_CONST               4 (None)
             42 RETURN_VALUE

dis分析后的结果 有三列分别是 行号 偏移量 指令 和 参数(目标对象)

我们主要看第三行.发现不同的地方

INPLACE_ADDBINARY_ADD.

这两个什么意思. 可以去官方手册中去查找 手册的地址:地址

官方手册中的说明:

BINARY_ADD Implements TOS = TOS1 + TOS.

INPLACE_ADD Implements in-place TOS = TOS1 + TOS.

这里有一个in-place的概念.那这个又是什么意思呢?继续看文档

In-place operations are like binary operations, in that they remove TOS and TOS1, and push the result back on the stack, but the operation is done in-place when TOS1 supports it, and the resulting TOS may be (but does not have to be) the original TOS1.

Binary operations remove the top of the stack (TOS) and the second top-most stack item (TOS1) from the stack. They perform the operation, and put the result back on the stack.

由于自己的水平问题,也没太理解这些意思.不过大致是说 INPLACE_ADD 这个操作是修改原数据,而非新建对象.BINARY_ADD会创建一个新对象。

为了验证这个结论,我们可以通过id函数来看看a,b变量的内存地址.

先对第一段程序进行分析.

a = [1, 2]
b = a
print('a:{0}\nb:{1}'.format(id(a),id(b)))
a += [3, 4]
print('a:{0}\nb:{1}'.format(id(a),id(b)))
print(a)
print(b)

结果是:

a:4339490312
b:4339490312
a:4339490312
b:4339490312
[1, 2, 3, 4]
[1, 2, 3, 4]

证明了那个观点.的确是修改原数据,而非创建一个新对象.我们在看看第二段程序

a = [1, 2]
b = a
print('a:{0}\nb:{1}'.format(id(a),id(b)))
a = a + [3, 4]
print('a:{0}\nb:{1}'.format(id(a),id(b)))
print(a)
print(b)

结果是:

a:4339600904
b:4339600904
a:4339673416
b:4339600904
[1, 2, 3, 4]
[1, 2]

果然是创建了一个新对象.结论正确.

dis模块是一个很强大的工具。对于我学习python的知识.很有帮助.

分析代码的方式不止命令行使用.也可以在代码中引用dis模块.然后使用dis.dis方法来分析代码.这里不过多介绍了。可以看文档了解.

这篇博客也就写这么多了。

学习之路漫长.本以为算是了解这些知识,但实际上还是有很多坑要爬.加油!

评论

还没有任何评论,你来说两句吧