
在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号