__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免费学习笔记(深入)”;
也可以直接返回底层资源,更贴近内置类型习惯:
支持模板化设计,基于标签调用数据 支持N国语言,并能根据客户端自动识别当前语言 支持扩展现有的分类类型,并可修改当前主要分类的字段 支持静态化和伪静态 会员管理功能,询价、订单、收藏、短消息功能 基于组的管理员权限设置 支持在线新建、修改、删除模板 支持在线管理上传文件 使用最新的CKEditor作为后台可视化编辑器 支持无限级分类及分类的移动、合并、排序 专题管理、自定义模块管理 支持缩略图和图
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__ 行为,无需手动实现类。









