__exit__ 返回 true 时异常被彻底丢弃;返回 none 或 false 则继续向上抛出;常见错误是仅记录日志却未显式返回 false,导致异常静默消失。

__exit__ 返回 True 时异常去哪儿了
Python 明确规定:__exit__ 返回 True 表示“这个异常我处理完了”,解释器收到这个信号后,就直接丢弃当前异常的全部信息(exc_type、exc_value、traceback),不再做任何栈展开或传播。它不是“捕获后重抛”,也不是“记录后忽略”——是彻底终止异常生命周期。
为什么返回 None 或 False 就不吞
因为 Python 的设计契约就是:只有显式返回 True 才代表“已处理”。其他所有情况(包括没写 return、写 return False、写 return 0)都会被当作“未处理”,解释器照常向上冒泡。
-
__exit__函数末尾没写return→ 实际返回None→ 异常继续抛 - 写了
return False或return 0→ 布尔上下文中为False→ 异常继续抛 - 写了
return "hello"→ 非空字符串转布尔为True→ 异常被吞(但这是危险写法,别这么干)
常见踩坑场景:本想记录日志,结果静默吞错
很多人在 __exit__ 里加了 logging.error(...) 就以为“处理过了”,却忘了补 return False 或干脆没写 return,结果日志打了,异常也消失了——调用方完全不知道出错了。
- 正确做法:记录完日志,显式写
return False(或什么都不写,靠默认None) - 错误做法:只写
print("cleanup")或self.close(),没控制返回值 - 更隐蔽的错:
if exc_type: log(); return True—— 这会把所有异常都吞掉,包括KeyboardInterrupt和SystemExit
只吞特定异常的写法要点
真要拦截某类异常(比如忽略 FileNotFoundError),必须严格比对 exc_type,且只对目标类型返回 True,其余一律不返回或返回 False:
def __exit__(self, exc_type, exc_value, traceback):
if exc_type is FileNotFoundError:
logging.info("Ignoring missing file")
return True
# 其他异常不做干预 → 自动返回 None → 继续冒泡
注意:exc_type is KeyError 比 isinstance(exc_value, KeyError) 更安全,因为前者不依赖实例,且能准确匹配异常类本身;而后者在异常被包装(如 raise new_exc from old_exc)时可能失效。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











