Python 使用 traceback 装饰器捕获并记录异常信息
本文介绍如何在 Python 中使用 traceback 模块和装饰器来捕获并记录函数异常信息。通过自定义装饰器,可将 ZeroDivisionError 等异常详情写入指定文件,解决线上 nohup 运行时无头排查困难的问题,并提供关于 except 作用域行为的深入解析。
Python 异常追踪与装饰器实现
首先观察以下函数示例。
def test():
sum = 3/0
if __name__ == '__main__':
test()
执行除以零的操作必然会导致异常,具体报错内容如下所示:
File "E:\Src\dongsheng\TestPython\testtrace_back.py", line 23, in <module> test() File "E:\Src\dongsheng\TestPython\testtrace_back.py", line 19, in test sum = 3/0 ZeroDivisionError: integer division or modulo by zero
上述报错信息是在集成开发环境(IDE)中直接运行脚本时显示的。然而,在实际生产环境中,脚本通常通过 nohup 命令后台启动,标准输出会被重定向至 nohup.out 文件。该文件往往包含大量杂乱日志,使得定位具体的异常堆栈变得非常困难。
Python 标准库提供了 traceback 模块,能够完美复现上述异常堆栈信息,并支持将输出重定向到指定文件。因此,我们可以编写一个装饰器,用于包装需要监控的函数。当被包装函数发生异常时,自动记录相关的异常详情。
#coding=utf-8
from functools import wraps
import traceback
def except_trace(filename):
def decorate(func):
@wraps(func)
def wrapper(*args,**kwargs):
try:
func(*args,**kwargs)
except:
fp = open(filename,'w')
traceback.print_exc(file=fp)
fp.close()
return wrapper
return decorate
@except_trace('1.txt')
def test():
sum = 3/0
if __name__ == '__main__':
test()
执行上述代码后,若发生异常,相关错误信息将被写入名为 1.txt 的文件中。该文件仅包含异常追踪信息,便于后续查看和分析。
Python except 作用域行为解析
补充知识:Python 中 except 子句的行为特性
这里展示一个常被讨论的 Python 行为细节。假设你期望以下 Python 代码执行什么结果?
如果你是从其他编程语言转向学习 Python 的开发者,可能会期望 except 子句引入一个嵌套的作用域,从而使得在子句中赋值给变量 e 不会影响外部作用域中已存在的 e 变量。然而,Python 的控制结构通常不引入嵌套作用域(列表推导式除外)。因此,具备一定 Python 经验的开发者可能会预期代码打印出 ZeroDivisionError 的实例。
实际上,在标准的 CPython 实现中,该代码不会打印任何内容;同时,最后一行代码会引发一个 NameError。这是否是一个 Bug?事实上,这是语言设计的有意为之。如果检查 except 子句生成的字节码,可以看到特定的指令行为:
当控制流退出 except 块时,Python 会从当前作用域中删除该变量名。这样设计的原因是:异常对象持有对当前栈帧的引用,而栈帧包含了作用域内的所有局部变量。由于 Python 主要采用引用计数机制管理内存,只要异常对象存在,当前作用域内的变量就无法被释放,直到下一轮垃圾回收运行(如果有的话)。当前的行为是在内存使用效率、实现复杂度和语言简洁性之间做出的权衡。尽管这带来了一些缺点,但我认为这体现了 Python 的一个特点:实用主义优先于纯粹性。
但这仅解释了 DELETE_NAME 指令的作用。为什么 CPython 要在删除变量之前先将 e 赋值为 None,即便随后立即删除了这个变量?设想 CPython 团队决定在 except 块结束时清理异常引用:
在 except 块的末尾,CPython 会尝试删除已经被移除的变量名 e。为了解决这个潜在问题,CPython 在删除 e 之前执行 e = None 赋值,以确保在尝试删除时 e 作为一个名称存在于作用域中。
以上关于 Python 追踪 except 信息的方式即为全部内容分享,希望能对大家有所帮助,也希望大家多多支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













