有没有办法挂钩CPython解释器,以便每个函数创建(def
,lambda
)导致调用我已定义的过程?不幸的是,sys.settrace
和sys.setprofile
似乎没有涵盖def
和lambda
。
似乎Python 3.7有f_trace_opcodes
...早期版本有什么选择吗?
在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
源,或检查字节码,以确定有内部定义的函数,但仍然没有办法在定义时调用您的钩子。NodeTransformer
在每个def
和lambda
节点之前或之后注入对某些function2的调用,然后编译转换后的树。但你也可以在bytecode
或byteplay
的字节码级别,在每个MAKE_FUNCTION
之前或之后进行。pdb
而不是编写自己的调试器。我不确定这是否会有所帮助,因为pdb
首先无法通过表达式的一部分。MAKE_FUNCTION
循环中的ceval
处理程序中添加断点。当然你的代码在调试器的解释器中 - 可以是gdb
和lldb
的Python,但它仍然不是你正在调试的Python解释器。并且,虽然可以递归地将代码评估到调试的解释器中(或触发其pdb
),但这并不容易,并且在解决问题时会在整个地方发生段错误。1.理解(除了列表推导,在2.x中)通过定义然后调用函数来实现。因此,任何依赖于MAKE_FUNCTION
操作码或类似操作的方法也会依赖于理解,而那些依赖源或AST解析的方法则不会(除非你明确地这样做)。
2.显然,您还需要在每个模块的顶部注入一个import
以使该功能可用,或者将该函数注入内置模块。
3.和MAKE_CLOSURE
一样,对于早期版本的Python。