Python异常沿调用栈向上冒泡传播,遇try...except捕获则停止,否则栈展开并触发退出;finally和上下文管理器仍执行;raise可重抛或链式关联异常;traceback记录完整调用链。

Python 中异常沿着调用栈向上传播,从发生异常的函数开始,逐层返回到上一级调用者,直到被 try...except 捕获,或传播到最外层未被捕获而终止程序。
异常传播的基本路径
当某处触发异常(如除零、索引越界),解释器立即停止当前函数执行,保存当前帧(frame)信息,并将异常对象“抛出”。它不会继续执行该函数中异常点之后的代码,而是跳转到最近的、能处理该异常类型的 except 子句。若当前函数没捕获,就退回到它的调用者,依此类推。
- 每层函数调用对应一个栈帧(frame),异常在帧之间“向上冒泡”
- 传播过程不依赖 return 或显式传递,是解释器自动行为
- 一旦被捕获,传播停止;若始终未捕获,最终触发
SystemExit或打印 traceback 后退出
未捕获时的栈展开(stack unwinding)
异常未被拦截时,Python 会自动清理调用栈:依次退出各层函数,释放其局部变量和帧对象。这个过程叫“栈展开”,但注意——__del__ 和 finally 仍会执行(只要帧还存在)。
-
finally块总会在对应try退出时运行,无论是否发生异常、是否被外层捕获 -
with语句的上下文管理器也会正常调用__exit__ - 但普通局部变量不会“清理”,只是随着帧销毁而自然不可达
手动控制传播:raise 和 raise ... from
在 except 块中,仅写 raise(无参数)会原样重抛当前异常,保留原始 traceback;而 raise NewException(...) from old_exc 则显式链式关联异常,形成因果关系链,在 traceback 中显示 The above exception was the direct cause of the following exception:。
立即学习“Python免费学习笔记(深入)”;
-
raise重抛不改变异常类型或消息,只延续原有位置信息 -
raise ... from None可抑制链式提示,让 traceback 看起来像首次抛出 - 链式异常有助于调试:比如底层 IO 错误引发上层业务逻辑错误
traceback 对象与栈帧信息
每个异常对象的 __traceback__ 属性指向一个 traceback 对象,它是一条单向链表,按传播逆序连接各栈帧(从异常发生点到最外层)。可通过 traceback.print_exc() 或 sys.exc_info() 获取并检查。
- 帧对象包含文件名、行号、函数名、局部变量(
f_locals),可用于动态分析 - 注意:交互式环境(如 IPython)可能缓存 traceback,导致多次
print_exc()输出相同内容 - 自定义异常处理器(如
sys.excepthook)可利用这些信息做日志或上报










