代码之家  ›  专栏  ›  技术社区  ›  user541686

有没有办法在CPython中执行函数创建代码?

  •  2
  • user541686  · 技术社区  · 7 年前

    有没有办法钩住CPython解释器,以便每个函数的创建( def , lambda )导致调用我定义的过程? sys.settrace sys.setprofile 不幸的是,这两者似乎都没有涵盖 定义 λ .

    更新:

    似乎python3.7已经 f_trace_opcodes

    1 回复  |  直到 5 年前
        1
  •  5
  •   abarnert    7 年前

    没有等同于 opcode 在3.7之前的版本中进行跟踪。如果有的话,这个特性本来就不会添加到3.7中。

    如果您可以升级到3.7,那么您想要的很简单:

    def tracefunc(frame, event, arg):
        if event == 'call':
            frame.f_trace_opcodes = True
        elif event == 'opcode':
            if frame.f_code.co_code[frame.f_lasti] == dis.opmap['MAKE_FUNCTION']:
                makefunctiontracefunc(frame)
        return tracefunc
    sys.settrace(tracefunc)
    

    能够 当然,这取决于你想要这样做的理由,但没有一个是简单的:

    • 使用 line 跟踪,并检查代码直到下一行。这对我来说是微不足道的 def lambda (四)理解 1 λ ast.parse 源代码,或者检查字节码,以确定其中是否定义了函数,但在定义时仍然无法正确调用钩子。
    • 不使用跟踪,而是编写一个导入钩子,在导入代码时修改代码。最简单的方法可能是在AST级别:在解析源代码之后,使用 NodeTransformer 每次之前或之后 定义 λ 节点,然后编译转换后的树。但也可以在字节码级别使用 bytecode byteplay MAKE_FUNCTION .
    • 脚本 pdb 而不是编写自己的调试器。我不确定这是否有用,因为 pdb公司
    • 生成函数 ceval 调用代码的循环。当然,您的代码在调试器的解释器中,它可以是Python gdb lldb ,但仍然不是 相同的 pdb公司

    1理解(2.x中的列表理解除外)是通过定义然后调用函数来实现的。所以,任何依赖于 操作码或类似的代码也会引发理解,而那些依赖于源代码或AST解析的代码则不会(当然,除非您显式地这样做)。

    2显然你还需要注射 import 在每个模块的顶部,使该函数可用,或将该函数注入到内置模块中。

    MAKE_CLOSURE ,用于早期版本的Python。