在Python开发中,我们有时需要获取代码执行的上下文信息,例如某个函数被调用时,是哪一行代码触发了这次调用。inspect 模块提供了一些工具,例如 inspect.currentframe().f_back.f_lineno 可以获取当前函数调用者(即上一层堆栈帧)的行号。然而,这个方法返回的是调用函数本身的行号,而非调用前执行的最后一条语句的行号。
考虑以下场景:
Line 1: if True: Line 2: print("Expecting the line no = 2") # 我们期望获取的行号 Line 3: else: Line 4: pass Line 5: log() # 调用 log() 函数的行
在这种情况下,inspect.currentframe().f_back.f_lineno 会返回 log() 函数所在的行号(即第5行),而不是我们期望的第2行。要获取第2行这样的“前一条语句”的行号,我们需要更深入地追踪Python的执行流程。
Python的 sys 模块提供了一个强大的调试钩子:sys.settrace()。这个函数允许我们设置一个全局的追踪函数,每当Python解释器执行到新的代码行、调用函数、返回函数或发生异常时,都会回调这个追踪函数。通过巧妙地利用这一机制,我们可以实现对代码执行路径的精确记录。
立即学习“Python免费学习笔记(深入)”;
sys.settrace(trace_func) 接收一个可调用对象 trace_func 作为参数。trace_func 的签名通常是 trace_func(frame, event, arg):
trace_func 必须返回自身或另一个追踪函数,以继续追踪。如果返回 None,则停止追踪。
为了获取函数调用前一行的行号,我们需要一个追踪函数来:
下面是一个实现这个逻辑的 Tracer 类:
import sys from collections import deque class Tracer: def __init__(self): # 使用 deque 存储行号,maxlen=2 确保只保留最近的两条记录 # 这样当 log() 被调用时,linenos[0] 就是调用前的那一行 self.linenos = deque(maxlen=2) # 存储 log 函数的代码对象,用于在 trace 函数中进行排除 self.log_code = None def trace(self, frame, event, arg): # 仅处理 'line' 事件,即代码执行到新的一行 if event == 'line': # 检查当前帧的代码对象是否为 log() 函数的代码对象 # 如果不是 log() 函数内部的行,则记录 if frame.f_code is not self.log_code: self.linenos.append(frame.f_lineno) # 必须返回自身,以确保追踪持续进行 return self.trace def log(self): # 确保 log_code 在第一次调用 log 时被设置 if self.log_code is None: self.log_code = self.log.__code__ # 在 log 函数内部,我们可以访问 self.linenos[0] 来获取调用前的行号 print(f"调用 log() 函数前执行的行号是: {self.linenos[0]}") # 实例化 Tracer tracer = Tracer() # 设置全局追踪函数 # sys.settrace 会在所有新的线程和新的帧中启用追踪 sys.settrace(tracer.trace) # 示例代码 # 这里的 sys._getframe().f_trace = tracer.trace 也是一种局部激活追踪的方式, # 它将当前帧及其子帧的追踪函数设置为 tracer.trace。 # 在本例中,两种设置方式结合使用,确保了追踪的全面性。 sys._getframe().f_trace = tracer.trace if True: # 假设此行位于文件的第 21 行 assert True else: pass # 调用 log 函数 tracer.log() # 停止全局追踪,避免对后续代码产生不必要的影响 sys.settrace(None)
代码解释:
运行上述代码,如果 assert True 语句位于示例文件的第21行,输出将是:调用 log() 函数前执行的行号是: 21。
通过 sys.settrace 结合精心设计的追踪逻辑,我们能够克服 inspect 模块在获取“前一条语句”行号方面的局限性,实现了对Python代码执行流程的精确监控。这对于高级调试、代码分析或自定义日志记录等场景非常有用。
以上就是Python中利用 sys.settrace 精准获取函数调用前一行的代码行号的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号