
finally 块在异常传播过程中自底向上逐层执行,无论异常是否被捕获;当 RecursionError 触发时,解释器会沿调用栈回溯,依次执行每一层未完成的 finally,因此 n=1 和 n=2 的打印语句得以输出。
`finally` 块在异常传播过程中**自底向上逐层执行**,无论异常是否被捕获;当 `recursionerror` 触发时,解释器会沿调用栈回溯,依次执行每一层未完成的 `finally`,因此 `n=1` 和 `n=2` 的打印语句得以输出。
在 Python 的异常处理模型中,finally 并非“仅在逻辑流程自然结束时执行”,而是具有强保证性(guaranteed execution)的清理机制——只要该 try 语句块已开始执行(即进入 try),无论后续是正常返回、return/break/continue 跳出,还是抛出任何异常(包括未捕获的 RecursionError、MemoryError 等),其对应的 finally 块都会被执行(除非进程被强制终止,见后文例外)。
回到你的示例代码:
def divisive_recursion(n):
try:
if n <= 0:
return 1
else:
return n + divisive_recursion(n // divisive_recursion(n - 1))
except ZeroDivisionError:
return -1
finally:
if n == 2:
print("Finally block executed for n=2")
elif n == 1:
print("Finally block executed for n=1")当调用 divisive_recursion(5) 时,递归深度迅速增长,最终因栈溢出触发 RecursionError。关键在于:该异常并非“瞬间崩溃”,而是沿调用栈逐层向上冒泡。每层函数在退出前,只要其 try 已启动,就必须执行 finally —— 这是 Python 解释器在异常传播路径上的强制保障。
我们可通过简化版递归验证这一行为:
立即学习“Python免费学习笔记(深入)”;
def demo_finally_propagation(n):
print(f"→ Entering demo({n})")
try:
if n == 0:
raise RecursionError("Stack exhausted at base")
demo_finally_propagation(n - 1)
finally:
print(f"← Exiting demo({n}) — finally executed")
# 输出节选(n=3时):
# → Entering demo(3)
# → Entering demo(2)
# → Entering demo(1)
# → Entering demo(0)
# ← Exiting demo(0) — finally executed
# ← Exiting demo(1) — finally executed
# ← Exiting demo(2) — finally executed
# ← Exiting demo(3) — finally executed
# Traceback (most recent call last): ...可见:finally 在异常被抛出后、控制权交还给上层前立即执行,且按调用栈逆序(LIFO)完成全部挂起的清理动作。
⚠️ 注意:finally 的“必定执行”有明确边界。以下场景会导致 finally 完全跳过:
- 进程被
SIGKILL(kill -9)强制终止; - 调用
os._exit()(绕过 Python 运行时,不触发任何清理); - 解释器遭遇致命错误(如 C 层段错误);
- 当前线程被
threading.Thread._stop()(已弃用)等非协作方式终结。
✅ 正确实践建议:
- 将资源释放(如
file.close()、conn.close())、状态重置、日志记录等关键清理逻辑放入finally; - 避免在
finally中引发新异常(可能掩盖原始错误); - 若需区分“正常退出”与“异常退出”,可结合
else子句(仅try无异常时执行)或使用标志变量; - 对于深度递归,优先考虑迭代改写或增加
sys.setrecursionlimit()(谨慎使用)以规避栈溢出。
总之,finally 是 Python 异常安全(exception safety)的基石之一——它不依赖逻辑分支的真假判断,而依赖运行时控制流的结构完整性。理解其在异常传播链中的“回溯式执行”特性,是编写健壮、可维护代码的关键。


















