AI大模型入门-Python进阶-上下文管理与with语句 视频链接不如语冰https://space.bilibili.com/70431433?spm_id_from333.1007.0.0文章代码链接https://github.com/zyf-ngu/Qmatter7上下文管理与with语句上下文管理是一种用于管理资源如文件、网络连接、锁等的机制它确保在代码块执行前后进行正确的资源分配和释放即使代码块中发生了异常也是如此。 在Python中上下文管理是通过with语句来实现的。with语句允许我们定义一个执行上下文在该上下文中我们可以确保资源的获取和释放是自动完成的。 即在with语句中我们只需要关注资源或对象本身的操作这点和普通方法一致系统自动释放资源和对象这点在普通方法中需要通过try except和finally实现即try实现功能except处理异常finally释放资源。上下文管理器的基本结构上下文管理的基本结构由两个特殊方法组成__enter__和__exit__。这两个方法定义在上下文管理器对象中。1. __enter__(self):当进入with语句块时会调用这个方法。该方法返回的资源是类吗会被赋值给as后面的变量如果有的话。 通常在这个方法中获取资源如打开文件。2. __exit__(self, exc_type, exc_value, traceback):当离开with语句块时无论是正常结束还是因为异常都会调用这个方法。参数exc_type, exc_value, traceback分别表示异常类型、异常值和调用栈。如果没有异常发生这三个参数都是None。 如果该方法返回True则表示异常已经被处理不会继续向外传播如果返回False则异常会被重新抛出如果没有异常返回什么都可以。通常在这个方法中释放资源如关闭文件。上下文管理器的种类除了使用类定义上下文管理器Python还提供了contextmanager装饰器在contextlib模块中可以快速创建基于生成器的上下文管理器。这种上下文管理器使用yield语句将函数分成两部分yield之前的部分相当于__enter__之后的部分相当于__exit__。方式1类实现完整控制特点显式定义__enter__和__exit__拥有完整异常处理能力支持状态管理class FileManager:def __init__(self, filename):self.filename filenameself.file Nonedef __enter__(self):print(打开文件...)self.file open(self.filename)return self.file # 返回资源对象def __exit__(self, exc_type, exc_val, exc_tb):print(关闭文件...)if self.file:self.file.close()# 处理异常返回True则阻止异常传播if exc_type:print(f发生异常: {exc_type})return False # 不屏蔽异常# 使用示例with FileManager(test.txt, w) asf:f.write(Hello Context!)# 即使发生异常文件也会关闭# 触发异常测试: 1/0print(操作完成)f是返回的资源名称可任意取f.write是该资源自己拥有的方法。方式2生成器实现简洁方案特点使用contextlib.contextmanager装饰器用yield分隔资源获取/释放代码更简洁例1from contextlib import contextmanagercontextmanagerdef file_manager(filename, mode):try:print(打开文件...)f open(filename, mode)yield f# 返回资源except Exception as e:print(f发生异常: {type(e).__name__})finally:print(关闭文件...)f.close()# 使用示例with file_manager(test.txt, a) as f:f.write(\nAppend content)# 触发异常测试: int(abc)# 传统方式易出错file open(data.txt)try:data file.read()# 若此处抛出异常file.close() 可能不被执行finally:file.close()# 必须手动确保关闭装饰器实现的上下文管理与普通的 try...except...finally 语句相比核心优势在于代码复用性、可读性和扩展性尤其更符合 “关注点分离” 的设计原则。以下从具体场景对比两者的优势普通 try...except 需要在每次使用资源时重复编写 “获取 - 清理” 逻辑而装饰器实现的上下文管理可以将这部分逻辑封装成通用工具在多个地方复用。普通 try...except 会将 “业务逻辑” 和 “资源管理逻辑” 混在一起而上下文管理通过 with 语句清晰分离两者让代码意图更明确。阅读代码时无需关注 “连接如何创建 / 关闭”“异常如何处理”只需聚焦 with 块内的核心业务逻辑降低理解成本。普通 try...except 依赖开发者手动编写 finally 块来释放资源容易因疏忽导致资源泄漏如忘记写 f.close()而上下文管理通过装饰器强制封装了清理逻辑无论开发者是否记得资源都会被自动释放。上下文管理通过装饰器的 finally 块或类实现的 __exit__强制执行清理操作从机制上避免了人为遗漏尤其适合团队协作确保所有人都遵循资源管理规范。装饰器实现的上下文管理可以轻松扩展支持嵌套、组合等复杂场景而普通 try...except 嵌套会导致代码臃肿“金字塔问题”。维度装饰器上下文管理普通try...except代码复用一次封装多处复用每次使用需重复编写资源管理逻辑可读性分离业务逻辑与资源管理意图明确逻辑混杂需通读代码才能理解意图资源安全强制自动释放避免人为失误依赖手动编写 finally易遗漏复杂场景支持简洁支持嵌套、组合等场景嵌套层级深代码臃肿例2from contextlib import contextmanagercontextmanagerdef session_scope():# 创建新的数据库会话相当于 __enter__ 方法session SessionLocal()try:# 将会话传递给 with 代码块使用yield session# 暂停执行将会话对象传递给 with 块# 代码块无异常时提交事务yield 之后的部分相当于 __exit__ 中的正常退出逻辑session.commit()except:# 发生异常时回滚事务session.rollback()# 重新抛出异常raisefinally:# 始终关闭会话释放连接相当于 __exit__ 中的清理逻辑session.close()with语句用法with 语句对资源的类型没有限制只要上下文管理器的 __enter__ 方法或装饰器中的 yield 语句返回的是一个合法对象就可以作为资源变量。这个对象可以是基础类型如文件对象、整数容器类型如列表、字典可调用对象如函数、类实例方法自定义类实例等。当资源变量是函数时它的作用通常是在 with 块内提供与当前上下文相关的操作如示例中打印临时目录信息同时享受上下文管理器的资源自动管理能力with类名参数/函数名参数as 变量:代码块# 等价于manager 上下文管理器()变量 manager.__enter__()try:代码块finally:manager.__exit__(异常信息)类名参数/函数名参数上面已经介绍了就是上下文管理器的2种方式那么后面这个as 有什么作用呢as关键字的使用场景情况是否使用as说明需要访问管理器返回值必须使用当 __enter__() 返回的值需要在代码块中使用时仅需资源管理可省略不需要使用管理器返回值时当需要直接操作上下文管理器返回的资源对象时# 文件操作需要文件对象进行读写with open(test.txt, w) asfile: # as 接收 open() 返回的文件对象file.write(Hello, World!) # 操作文件对象# 退出 with 后文件自动关闭当只需确保资源清理不需要操作管理器返回值时比如锁操作# 锁操作只需确保锁被释放无需直接操作锁对象import threadinglock threading.Lock()with lock: # 不需要 as因为不需要操作锁对象print(临界区代码执行中)# 退出 with 后锁自动释放class Timer:def __enter__(self):self.start time.time()def __exit__(self, *args):elapsed time.time() - self.startprint(f代码块耗时: {elapsed:.2f}秒)with Timer(): # 不需要 as因为不关心返回值time.sleep(1.5) # 模拟耗时操作输出代码块耗时: 1.50秒2. 异常处理更健壮问题解决在 __exit__() 中可统一处理异常如回滚事务、日志记录。原理__exit__() 接收异常信息可通过返回 True 抑制异常。class DatabaseTransaction:def __enter__(self):self.conn sqlite3.connect(db.db)return self.conn.cursor()def __exit__(self, exc_type, exc_val, exc_tb):if exc_type:# 发生异常时回滚self.conn.rollback()else:# 否则提交self.conn.commit()self.conn.close()with DatabaseTransaction() as cursor:cursor.execute(DELETE FROM users)# 若此处失败自动回滚