上下文管理器是实现了 __enter__ / __exit__ 协议的对象,配合 with 语句保证"进入时获取资源、退出时必然释放",即使中途抛异常也会执行清理。with open(f) as fp 等价于:__enter__ 的返回值绑定到 as 变量,块结束或异常时调用 __exit__(exc_type, exc_val, exc_tb);__exit__ 返回 True 表示吞掉异常。
两种实现方式:
# 1. 类实现协议
class Timer:
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, *exc):
print("耗时:", time.time() - self.start)
return False # 不吞异常
# 2. contextlib 生成器写法,更简洁
from contextlib import contextmanager
@contextmanager
def timer():
start = time.time()
try:
yield # yield 前是 __enter__,后是 __exit__
finally:
print("耗时:", time.time() - start)
要点:yield 处若收到异常会被 throw 进生成器,所以要用 try/finally 包裹才能保证清理;@contextmanager 方式省样板但语义不变。常见应用:文件、锁、数据库事务、临时修改状态(decimal.localcontext、测试 mock 的 patch)。追问方向:__exit__ 返回值语义、异步上下文管理器 async with 与 __aenter__/__aexit__、ExitStack 动态管理多个上下文。