__enter__ 方法的核心作用是定义进入 with 语句块时执行的操作并决定返回给 as 后变量的对象;它在 with 开始时自动调用,返回值绑定到 as 变量,默认返回 none,常用于资源获取或状态切换,需与 __exit__ 配合确保正确清理。

自定义上下文管理器的 __enter__ 方法,核心作用是**定义进入 with 语句块时要执行的操作,并决定返回给 as 后变量的对象**。
__enter__ 的基本职责
__enter__ 是一个实例方法,它在 with 语句开始执行时被自动调用。它的返回值会绑定到 as 后面的变量上。如果没写 return,默认返回 None。
- 常用于资源获取:打开文件、连接数据库、加锁、切换状态等
- 返回值可以是自身(
return self),也可以是其他对象(如文件句柄、连接实例) - 若抛出异常,
with块不会执行,直接进入异常处理流程
常见实现方式
最典型的模式是让 __enter__ 返回 self,方便在 with 块中调用该对象的方法:
class DatabaseConnection: def __init__(self, url): self.url = url self.conn = None <pre class='brush:python;toolbar:false;'>def __enter__(self): self.conn = connect_to_db(self.url) # 实际建立连接 return self # 允许 with db as conn: 中的 conn 调用 db 的方法 def __exit__(self, exc_type, exc_val, exc_tb): if self.conn: self.conn.close()
立即学习“Python免费学习笔记(深入)”;
也可以直接返回底层资源,更贴近内置类型习惯:
class FileManager: def __init__(self, path, mode='r'): self.path = path self.mode = mode self.file = None <pre class='brush:python;toolbar:false;'>def __enter__(self): self.file = open(self.path, self.mode) # 打开文件 return self.file # with fm as f: 中的 f 就是 file 对象 def __exit__(self, *args): if self.file: self.file.close()
立即学习“Python免费学习笔记(深入)”;
注意点和易错细节
__enter__ 虽然看起来简单,但几个关键细节容易影响行为:
- 不要在
__enter__里做耗时或可能失败但未处理的操作——除非你希望它直接中断with流程 - 如果
__enter__返回了对象 A,而__exit__需要清理另一个对象 B,需确保 B 在 A 的生命周期内可访问(通常存为实例属性) - 不建议在
__enter__中修改外部状态(如全局变量),这会让上下文管理器难以测试和复用 - 与
__exit__配合时,要保证无论__enter__返回什么,__exit__都能正确清理已初始化的资源
替代方案:contextlib.contextmanager
如果逻辑简单,用生成器函数配合 @contextmanager 更简洁,yield 之前的代码相当于 __enter__,之后相当于 __exit__:
from contextlib import contextmanager <p>@contextmanager def timer(): start = time.time() try: yield lambda: time.time() - start # <strong>enter</strong> 返回一个计算耗时的函数 finally: pass # <strong>exit</strong> 清理逻辑(这里不需要)</p><h1>使用</h1><p>with timer() as elapsed: time.sleep(1) print(f"耗时:{elapsed():.2f}s")
这种写法隐式定义了 __enter__ 行为,无需手动实现类。