有没有办法在Python中创建函数创建代码?

问题描述 投票:3回答:1

有没有办法挂钩CPython解释器,以便每个函数创建(deflambda)导致调用我已定义的过程?不幸的是,sys.settracesys.setprofile似乎没有涵盖deflambda

Update:

似乎Python 3.7有f_trace_opcodes ...早期版本有什么选择吗?

python hook cpython tracing
1个回答
4
投票

在3.7之前的版本中没有相当于opcode的跟踪。如果有,则首先不会将该功能添加到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(和comprehensions1)来说,这将是一个巨大的痛苦,因为lambda(甚至其中五个)可以出现在声明的中间。您可以ast.parse源,或检查字节码,以确定有内部定义的函数,但仍然没有办法在定义时调用您的钩子。
  • 不要使用跟踪,而是编写一个导入钩子,在导入时修改代码。执行此操作的简单方法可能是在AST级别:解析源代码后,使用NodeTransformer在每个deflambda节点之前或之后注入对某些function2的调用,然后编译转换后的树。但你也可以在bytecodebyteplay的字节码级别,在每个MAKE_FUNCTION之前或之后进行。
  • 脚本pdb而不是编写自己的调试器。我不确定这是否会有所帮助,因为pdb首先无法通过表达式的一部分。
  • 调试CPython本身,并在调用代码的MAKE_FUNCTION循环中的ceval处理程序中添加断点。当然你的代码在调试器的解释器中 - 可以是gdblldb的Python,但它仍然不是你正在调试的Python解释器。并且,虽然可以递归地将代码评估到调试的解释器中(或触发其pdb),但这并不容易,并且在解决问题时会在整个地方发生段错误。

1.理解(除了列表推导,在2.x中)通过定义然后调用函数来实现。因此,任何依赖于MAKE_FUNCTION操作码或类似操作的方法也会依赖于理解,而那些依赖源或AST解析的方法则不会(除非你明确地这样做)。

2.显然,您还需要在每个模块的顶部注入一个import以使该功能可用,或者将该函数注入内置模块。

3.和MAKE_CLOSURE一样,对于早期版本的Python。

© www.soinside.com 2019 - 2024. All rights reserved.