python - 有没有办法使 dis.dis() 递归打印代码对象?

标签 python recursion disassembly

我一直在使用 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() 递归打印代码对象?也就是说,如果我有嵌套的代码对象,它将打印出所有 代码对象的字节码,而不是在顶级代码对象处停止。我主要喜欢装饰器、闭包或生成器推导式等事物的此功能。

看来最新版本的 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 文章记下了这一点:

The dis() function now is able to disassemble nested code objects (the code of comprehensions, generator expressions and nested functions, and the code used for building nested classes). (Contributed by Serhiy Storchaka in bpo-11822.)

但是,Python 3.7 还没有正式发布,如果你不想或不能使用 Python 3.7 怎么办?有没有办法在 Python 的早期版本(例如 3.5 或 2.7)中使用旧的 dis.dis() 来完成此操作?

最佳答案

你可以这样做(Python 3):

import dis

def recursive_dis(code):
    print(code)
    dis.dis(code)

    for obj in code.co_consts:
        if isinstance(obj, type(code)):
            print()
            recursive_dis(obj)

https://repl.it/@solly_ucko/Recursive-dis

请注意,您必须使用 f.__code__ 而不是 f 来调用它。例如:

def multiplier(n):
    def inner(multiplicand):
        return multiplicand * n
    return inner

recursive_dis(multiplier.__code__)

关于python - 有没有办法使 dis.dis() 递归打印代码对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44877745/

相关文章:

python - ravendb python api,查询总是返回128

linux - GDB Edit Assembly (Intel) 永久和临时

assembly - 如何使用 AVR 的 gnu 汇编器相对于 PC 跳转?

ruby - ruby 中的递归乘数

ios - 如何在 swift 中处理递归函数中的不同线程?

c - 将汇编代码逆向工程为 C

python - 在 Python 2.7 中使用 raw_input() 读入德语变音符号

python - 将 Python 中的打印列表转换回实际列表的最佳方法是什么

python - 使用 Python 列表推导计算列表中的正整数元素

java - 用Java实现的计算斐波那契数列的算法给出了奇怪的结果