绝大多数情况只需 traceback.format_exc();它在 except 块中返回当前异常的完整堆栈字符串,必须在异常活跃时调用,否则返回空字符串。

用 traceback.format_exc() 拿到当前异常的完整堆栈字符串
当异常刚发生、还在 except 块里时,traceback.format_exc() 是最直接的方式。它等价于 traceback.print_exc(file=sys.stdout),但返回字符串而非直接打印,方便记录或传输。
常见错误是试图在异常处理之外调用它——此时返回空字符串,因为没有活跃异常。
- 必须在
except或finally中调用(且异常尚未被清除) - 不带参数时默认捕获最近一次异常;传入
exc_info=...可复用旧异常信息 - 返回值是含换行符的完整字符串,可直接写入日志文件或发给监控系统
try:
1 / 0
except ZeroDivisionError:
import traceback
s = traceback.format_exc() # ✅ 正确:s 包含 'ZeroDivisionError: division by zero' 及所有帧
print(repr(s))
用 traceback.print_exception() 精确控制输出格式
当你需要把堆栈输出到特定文件、过滤掉某些帧,或和自定义上下文拼接时,traceback.print_exception() 更灵活。它接受 exc_type、exc_value、exc_traceback 三元组,允许你操作原始异常对象。
容易踩的坑是误传 sys.exc_info() 的结果却不解包——它返回的是元组,不能直接当参数传。
- 正确用法:
traceback.print_exception(*sys.exc_info(), file=f) - 可跳过前 N 个帧(如隐藏日志封装层):加参数
limit=-N - Python 3.10+ 支持
compact=True压缩重复路径,减小日志体积
在非异常上下文中获取当前调用栈(不含异常)
有时你想知道“代码执行到这里时,是谁调用了我”,比如调试装饰器或性能采样。这时不能用 format_exc(),而要用 traceback.format_stack()。
注意它返回的是当前执行点的栈帧列表(不含异常信息),最后一项是调用它的那行代码,不是最外层入口。
-
format_stack()返回字符串列表,每项对应一帧;format_list()可进一步美化 - 若只想要函数名和行号,用
inspect.currentframe().f_back配合f_code.co_name更轻量 - 频繁调用有性能开销,生产环境慎用于热点路径
捕获未处理异常(全局兜底)要改 sys.excepthook
主线程中没被 try/except 捕获的异常,会触发 sys.excepthook。想统一收集所有崩溃堆栈,就得重置它。
别直接覆盖 sys.excepthook = my_handler 后忘记调用原函数——这会导致默认打印消失,且 IDE 调试器可能失效。
- 推荐继承
sys.__excepthook__,仅添加日志逻辑 - 多线程中子线程异常不会走这里,需配合
threading.excepthook(Python 3.8+) - 异步任务(如
asyncio)需单独监听loop.set_exception_handler
实际用的时候,绝大多数情况只需要 traceback.format_exc() 就够了。真正难的是判断该在哪一层捕获、要不要重新抛出、以及堆栈里哪些帧属于框架代码该折叠——这些没法靠函数自动决定。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











