异常未被捕获时沿调用栈向上传播,直至被处理或程序终止并打印traceback;若except中不raise则异常结束,raise无参则原样重抛,raise新异常则替换原异常,可用raise...from保留上下文。

当程序中抛出一个异常但没有被当前的 try...except 捕获时,这个异常会向上传播,也就是沿着调用栈(call stack)逐层往回传递,直到遇到能处理它的 except 块,或者最终到达程序顶层。
如果一直没被捕获,Python 会终止程序,并打印完整的 traceback(错误追踪信息),包括异常类型、消息和出错位置。
异常传播的路径
- 从异常发生的函数内部开始
- 如果当前函数没有
try...except捕获它,就返回到调用它的上一层函数 - 上一层函数同样检查是否有匹配的
except,没有就继续往上 - 如此反复,直到:
- 被某个
except捕获并处理 - 或者传播到最外层(比如模块顶层、交互式解释器),此时 Python 报错退出
- 被某个
例如:
def func_c():
raise ValueError("出错了")
def func_b():
func_c() # 这里不捕获,异常继续往外传
def func_a():
func_b() # 同样不捕获
func_a() # 最终异常在这里“暴露”,程序崩溃traceback 会显示 func_c → func_b → func_a → <module> 的完整链条。
被 except 捕获后,原异常去哪了?
- 如果你只是
except Exception:然后做点日志或提示,异常就结束了,不会继续传播 - 如果你在
except中 没重新抛出(比如没写raise),那它就真的“消失”了,控制流继续往下走 - 如果写了
raise(无参数),会原样重抛刚才那个异常,保持原始 traceback - 如果写了
raise 新异常,则旧异常被替换,traceback 从这里重新开始(除非用raise ... from ...链接)
特殊情况:finally 和 else
-
finally总是执行,哪怕有未捕获异常;但如果finally里也抛异常,它会覆盖前面的异常(原异常丢失) -
else只在没异常时运行,不影响异常流向
如何查看或保留原始异常?
- 用
sys.exc_info()可以获取当前异常的类型、值、traceback - 用
logging.exception()自动记录完整 traceback - 用
raise ... from original_exc显式关联新旧异常,避免丢失上下文
比如:
try:
risky_operation()
except KeyError as e:
raise RuntimeError("配置加载失败") from e这样 traceback 会同时显示 KeyError 和 RuntimeError,并标明因果关系。
不复杂但容易忽略。

















