Python中是否存在适用于类的contextlib.contextmanager版本?
用生成器定义类上下文管理器的实现方案
完全可以实现,不需要改变原有类实例化加with块的使用模式,也不需要修改__init__的原有逻辑,最常用的实现方式是在类内部封装一个被@contextlib.contextmanager装饰的生成器方法,再把__enter__和__exit__的逻辑透传给这个生成器上下文管理器即可。
实现示例
import contextlib class Client: def __init__(self, host: str, port: int): # __init__ 中正常编写初始化逻辑,比如参数存储、预校验等 self.host = host self.port = port # 初始化内部的上下文管理器实例 self._inner_cm = self._gen_context() @contextlib.contextmanager def _gen_context(self): # 此处编写上下文进入时的逻辑,比如建立连接、申请资源 self.connection = self._build_connection() try: # yield 返回的对象就是 with 块中 as 后拿到的实例,这里返回类自身即可 yield self except Exception as e: # 此处编写异常处理逻辑 self._handle_exception(e) # 不需要上层捕获异常可返回 True,需要向上抛出就执行 raise raise finally: # 此处编写退出时的清理逻辑,比如关闭连接、释放资源 self.connection.close() def __enter__(self): return self._inner_cm.__enter__() def __exit__(self, exc_type, exc_val, exc_tb): return self._inner_cm.__exit__(exc_type, exc_val, exc_tb) # 以下为类的业务方法示例 def _build_connection(self): print(f"建立到 {self.host}:{self.port} 的连接") return object() def _handle_exception(self, e: Exception): print(f"捕获到异常: {str(e)}") def blah(self): print("执行 Client 类的 blah 方法")
使用方式
和常规的类上下文管理器使用模式完全一致,不需要做任何改动:
with Client("127.0.0.1", 8080) as c: c.blah()
注意事项
- 这种实现的语法和独立上下文管理器的写法完全一致,没有额外学习成本,所有状态都统一在生成器方法中管理,逻辑清晰不易出错。
- 生成器的额外开销极低,和手写
__enter__、__exit__方法的性能几乎没有差异。 - 上述方案兼容Python 3.5及以上的绝大多数生产环境版本,无特殊依赖。
内容的提问来源于stack exchange,提问作者Att Righ
相关产品推荐
相关产品推荐

