Python 使用 traceback 装饰器捕获并记录异常信息

桃夭
桃夭
发布时间:2026-10-13| 5人浏览过
原创

本文介绍如何在 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 信息的方式即为全部内容分享,希望能对大家有所帮助,也希望大家多多支持本站。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。