如何使用sys.settrace跟踪全局作用域中的代码运行?

3
假设我有如下代码:
import sys

def printer(frame, event, arg):
    print(frame, event, arg)
    return printer

sys.settrace(printer)
x = 1
sys.settrace(None)

自从

每当进入新的本地范围时,都会调用trace函数(事件设置为“调用”)

上面的代码没有输出。请参阅我之前的问题

那么有没有办法跟踪全局作用域中的行,比如 x = 1

1个回答

4
sys.settrace设置全局追踪函数。每当进入新的Python堆栈帧时('call'事件),都会调用此追踪函数,并且其返回值是新范围的本地追踪函数。活动堆栈帧的本地追踪函数是用于所有其他事件类型的函数。您需要设置现有堆栈帧的本地追踪函数,但设置全局追踪函数无法帮助您完成此操作。要设置现有帧的本地追踪函数,可以将帧对象的f_trace属性手动分配给所需的函数。例如,要设置当前帧的本地追踪函数:
import sys
sys._getframe().f_trace = whateverfunc

请注意,如果没有全局跟踪函数,则不会调用本地跟踪函数,因此您还需要设置全局跟踪函数。(这似乎没有记录。)
您可以结合使用sys.settrace和手动f_trace分配来跟踪新的和现有的堆栈帧;例如,在'return'事件上,您可以检查要返回的帧的本地跟踪函数,并将该跟踪函数设置为您想要的任何内容。bdb debugger framework source code是如何处理跟踪函数的好例子。

谢谢。我使用 sys._getframe().f_trace = printer 替换了 sys.settrace(printer),但是仍然没有输出。我有什么误解吗? - laike9m
1
@laike9m:你还需要设置全局跟踪函数。如果没有全局跟踪函数,本地跟踪函数将不会被调用。这是 Python 调试支持中奇怪而未记录的细节之一。 - user2357112
哇,太疯狂了,非常感谢...这是发生这种行为的地方吗?https://github.com/python/cpython/blob/29500737d45cbca9604d9ce845fb2acc3f531401/Python/ceval.c#L4526 - laike9m
@laike9m:这是其中一个重要的部分。sys.settrace实现也很重要,特别是trace_trampoline,它是一个C级别的跟踪函数,不同于传递给settrace的Python级别函数,并且用于本地和全局跟踪函数调用。在ceval.c中查找call_trace也会出现一堆相关代码。 - user2357112

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接