必须实现__enter__和__exit__两个方法;__exit__返回true则吞异常,否则传播;@contextlib.contextmanager中yield前后分别对应__enter__和__exit__逻辑,需用try/finally保证清理。

直接说结论:必须实现 __enter__ 和 __exit__ 两个方法,缺一不可;用类比函数装饰器更直观,但别误以为加了 @contextlib.contextmanager 就不用管异常处理逻辑。
为什么 __exit__ 的返回值会影响异常传播
当 with 块中抛出异常时,__exit__(exc_type, exc_value, traceback) 会被调用。如果这个方法返回 True,异常就“被吞掉”,不会继续向上抛;返回 None 或 False,异常照常传播。
- 常见错误:在
__exit__里写了日志或清理逻辑后,忘了显式return False,结果异常消失得莫名其妙 - 典型场景:文件锁、数据库连接、临时目录——你通常希望资源释放成功,但异常仍要暴露给调用方
- 性能影响:返回
True不会提速,只是改变了控制流;滥用会导致调试困难
用 @contextlib.contextmanager 写法更简洁,但 yield 前后有严格分工
装饰器写法本质是把生成器函数转成上下文管理器,yield 之前的代码对应 __enter__,之后的 except/finally 块对应 __exit__。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
- 容易踩的坑:在
yield后面写普通语句(没包在try/finally或except里),这部分根本不会执行 - 参数差异:
yield value的value会成为with EXPR as value:中的value;不写yield就是as绑定None - 示例:
@contextlib.contextmanager def temp_file(): f = open("tmp.txt", "w") try: yield f # ← 这里交出控制权 finally: f.close() # ← 这里保证执行,无论是否异常
类实现 vs 装饰器实现:选哪个取决于复用性和状态管理需求
如果你的上下文管理器需要保存中间状态(比如计数器、缓存句柄、嵌套层级),类写法更自然;如果只是简单的一次性资源包装,装饰器更轻量。
- 类实现能直接访问实例属性,适合带配置的管理器(如
TimeoutManager(timeout=5)) - 装饰器写法无法在
yield前后共享局部变量,除非用闭包或外部容器,容易绕晕 - 兼容性注意:Python 3.7+ 对生成器上下文管理器的异常传播行为更严格,老代码若依赖隐式吞异常,升级后可能暴露问题
真正难的不是写出来,而是想清楚:资源释放逻辑是否和业务异常处理耦合?要不要让使用者感知到底层失败?这两点决定了 __exit__ 里到底该 return True 还是放行异常。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










