Chr*_*ean 5 python recursion disassembly
我一直在使用该dis模块来观察CPython字节码。但是最近,我注意到的某些不便行为dis.dis()。
以这个例子为例:我首先定义一个函数,multiplier其中包含嵌套函数inner:
>>> def multiplier(n):
def inner(multiplicand):
return multiplicand * n
return inner
>>>
Run Code Online (Sandbox Code Playgroud)
然后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
>>>
Run Code Online (Sandbox Code Playgroud)
如您所见,它反汇编了顶级代码对象。但是,它并没有拆卸inner。它只是表明它创建了一个名为的代码对象,inner并显示了代码对象的默认值(无信息)__repr__()。
有没有办法让我dis.dis()递归地打印代码对象?也就是说,如果我有嵌套的代码对象,它将打印出所有代码对象的字节码,而不是停止在顶级代码对象上。我主要希望此功能用于装饰器,闭包或生成器理解。
看来最新版本的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
Run Code Online (Sandbox Code Playgroud)
“ Python 3.7的新增功能”文章对此进行了说明:
该
dis()函数现在能够反汇编嵌套的代码对象(理解代码,生成器表达式和嵌套函数以及用于构建嵌套类的代码)。(由Serhiy Storchaka在bpo-11822中贡献。)
但是,除了尚未正式发布Python 3.7之外,如果您不想或者不能使用Python 3.7怎么办?是否可以使用旧版本的Python早期版本(例如3.5或2.7)来完成此操作dis.dis()?
首先,如果您需要此功能而不是交互式使用,我建议您从 Python 3.7 源代码复制代码并反向移植它(希望这并不困难)。
对于交互式使用,一个想法是使用通过内存值访问对象的方法之一,通过其内存地址获取代码对象,该地址打印在dis输出中。
例如:
>>> def func(a):
... def ifunc(b):
... return b + 10
... return ifunc
>>> import dis
>>> dis.dis(func)
2 0 LOAD_CONST 1 (<code object ifunc at 0x10cabda50, file "<stdin>", line 2>)
3 LOAD_CONST 2 ('func.<locals>.ifunc')
6 MAKE_FUNCTION 0
9 STORE_FAST 1 (ifunc)
4 12 LOAD_FAST 1 (ifunc)
15 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
这里我复制粘贴上面打印的代码对象的内存地址
>>> import ctypes
>>> c = ctypes.cast(0x10cabda50, ctypes.py_object).value
>>> dis.dis(c)
3 0 LOAD_FAST 0 (b)
3 LOAD_CONST 1 (10)
6 BINARY_ADD
7 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
警告:ctypes.cast如果您向解释器传递内存中不存在的内容(例如,因为它已被垃圾收集),则该行将导致解释器出现段错误。上述问题中的一些其他解决方案可能效果更好(我尝试了其中gc一个,但它似乎无法找到code对象)。
这也意味着如果您传递字符串,这将不起作用dis,因为当您尝试访问内部代码对象时,它们已经被垃圾收集。您需要向它传递一个真正的 Python 对象,或者,如果您有一个字符串,compile()则首先传递它。
| 归档时间: |
|
| 查看次数: |
521 次 |
| 最近记录: |