【发布时间】:2017-07-03 04:18:26
【问题描述】:
我一直在使用 dis 模块来观察 CPython 字节码。但最近,我注意到dis.dis() 的一些不便行为。
以这个例子为例:我首先定义了一个函数multiplier,其中包含一个嵌套函数inner:
>>> def multiplier(n):
def inner(multiplicand):
return multiplicand * n
return inner
>>>
然后我用dis.dis()来反汇编:
>>> from dis import dis
>>> dis(multiplier)
2 0 LOAD_CLOSURE 0 (n)
3 BUILD_TUPLE 1
6 LOAD_CONST 1 (<code object inner at 0x7ff6a31d84b0, file "<pyshell#12>", line 2>)
9 LOAD_CONST 2 ('multiplier.<locals>.inner')
12 MAKE_CLOSURE 0
15 STORE_FAST 1 (inner)
4 18 LOAD_FAST 1 (inner)
21 RETURN_VALUE
>>>
如您所见,它很好地反汇编了顶级代码对象。但是,它并没有反汇编inner。它只是表明它创建了一个名为 inner 的代码对象,并显示了代码对象的默认(无信息)__repr__()。
有没有办法让dis.dis() 递归地打印代码对象?也就是说,如果我有嵌套的代码对象,它将打印出 all 的代码对象的字节码,而不是在顶级代码对象处停止。我主要喜欢这个特性,比如装饰器、闭包或生成器理解。
看来最新版本的 Python - 3.7 alpha 1 - 具有我想要的 dis.dis() 的行为:
>>> def func(a):
def ifunc(b):
return b + 10
return ifunc
>>> dis(func)
2 0 LOAD_CONST 1 (<code object ifunc at 0x7f199855ac90, file "python", line 2>)
2 LOAD_CONST 2 ('func.<locals>.ifunc')
4 MAKE_FUNCTION 0
6 STORE_FAST 1 (ifunc)
4 8 LOAD_FAST 1 (ifunc)
10 RETURN_VALUE
Disassembly of <code object ifunc at 0x7f199855ac90, file "python", line 2>:
3 0 LOAD_FAST 0 (b)
2 LOAD_CONST 1 (10)
4 BINARY_ADD
6 RETURN_VALUE
What’s New In Python 3.7 文章记录了这一点:
dis()函数现在能够反汇编嵌套代码对象(理解代码、生成器表达式和嵌套函数,以及用于构建嵌套类的代码)。 (由 Serhiy Storchaka 在 bpo-11822 中贡献。)
但是,除了 Python 3.7 还没有正式发布之外,如果你不想或不能使用 Python 3.7 怎么办?有没有办法在 Python 的早期版本(例如 3.5 或 2.7)中使用旧的 dis.dis() 来实现这一点?
【问题讨论】:
标签: python recursion disassembly