Python 的 with ... as ... 上下文管理器

一、核心作用

  • 自动执行「进入操作」(如打开文件、创建连接)和「退出操作」(如关闭文件、释放连接)
  • 即使代码块中发生异常,也能保证退出操作被执行(相当于自带 try-finally 但更简洁)

二、 基本语法结构

python 复制代码
with 上下文表达式 as 变量名: 
    # 代码块(使用资源的逻辑) 
# 代码块结束后,自动执行退出操作(无需手动关闭)
  • 「上下文表达式」:返回一个上下文管理器对象 (如 open()、自定义的 对象 实例)
  • 变量名」:可选,接收上下文管理器的 __enter__() 方法返回的值(不是管理器对象本身

三、工作原理

一个对象能被with使用,必须实现两个特殊方法

  1. __enter__(self):进入 with 代码块时执行。
    • 负责初始化资源(如打开文件、连接数据库)
    • 返回的值会赋值给 as 后的变量名
  2. __exit__(self, exc_type, exc_val, exc_tb):退出 with 代码块时执行(无论正常结束还是异常结束)
    • 负责释放资源(如关闭文件、断开连接)
    • 接收异常信息,可返回 True 表示忽略异常。

示例:自定义简单上下文管理器

python 复制代码
class MyFileReader: 
    def __init__(self, file_path):
        self.file_path = file_path 
        self.file = None # 进入with代码块时执行 
    def __enter__(self): 
        self.file = open(self.file_path, 'r', encoding='utf-8') 
        return self.file # 返回文件对象,赋值给as后的变量 # 退出with代码块时执行 
    def __exit__(self, exc_type, exc_val, exc_tb): 
        if self.file: 
            self.file.close() # 自动关闭文件 
        # 若返回True,会忽略代码块中的异常;返回None/False则会抛出异常 
        return False 
# 使用 with 
MyFileReader('test.txt') as f: 
    content = f.read() # 直接使用__enter__返回的文件对象 
    # 代码块结束后,自动调用__exit__关闭文件

四、常见使用场景

1.操作文件

替代手动open()/close(),避免忘记关闭文件

python 复制代码
# 正确用法:自动关闭文件 
with open('test.txt', 'r', encoding='utf-8') as f: 
    content = f.read() 
# 等价于(但更简洁) 
f = open('test.txt', 'r', encoding='utf-8') 
try: 
    content = f.read() 
finally: 
    f.close()

2.使用自定义工具类

只有实现了 __enter__ 和 __exit__,才能直接用 with

3.多资源同时管理

可在一个 with 中管理多个资源(用逗号分隔),按顺序进入、逆序退出:

python 复制代码
# 同时打开两个文件,自动关闭 
with open('a.txt', 'r') as f1, open('b.txt', 'w') as f2: 
    content = f1.read() 
    f2.write(content)

4. 数据库连接/网络连接

自动释放连接,避免连接池耗尽:

python 复制代码
import pymysql

with pymysql.connect(host='localhost', user='root', password='123456', db='test') as conn:
    with conn.cursor() as cursor:
        cursor.execute('SELECT * FROM users')
        result = cursor.fetchall()
# 自动关闭cursor和conn

五、关键注意事项

  1. as 后的变量是 __enter__ 的返回值,不是上下文管理器对象:
    • 如 open() 的 __enter__ 返回文件对象,所以 as f 中 f 是文件对象,不是 open() 的返回值
    • 你的 MyFileReader 中 __enter__ 返回 self,所以 reader 是 MyFileReader 实例,可调用其方法。
  2. 异常处理
    • 代码块中发生异常时,__exit__ 仍会执行(保证资源释放)
    • 若 __exit__ 返回 True,异常会被静默处理(不抛出);返回 False 或 None,异常会正常抛出
  3. 并非所有对象都能用于 with
    • 必须实现 __enter__ 和 __exit__ 方法(即「上下文管理器协议」)
    • 常见支持的对象:open()、threading.Lock、pymysql.connect、自定义实现协议的类
  4. 适用于「需要成对操作」的场景
    • 打开 / 关闭、连接 / 断开、加锁 / 解锁等,用 with 能简化代码并避免遗漏

六、进阶:用contextlib简化自定义上下文管理器

如果不想手动实现 __enter__ 和 __exit__,可使用 contextlib.contextmanager 装饰器(基于生成器):

python 复制代码
from contextlib import contextmanager

@contextmanager
def my_file_reader(file_path):
    # 相当于__enter__的逻辑
    f = open(file_path, 'r', encoding='utf-8')
    yield f  # 返回值赋值给as后的变量,暂停在这里执行代码块
    # 代码块结束后,执行以下(相当于__exit__的逻辑)
    f.close()

# 使用方式不变
with my_file_reader('test.txt') as f:
    content = f.read()
相关推荐
实名上网宋凯宣9 小时前
Django
后端·python·django
如若12310 小时前
【论文复现】CoFailMed:从零复现医学图像分割的共享失败审计,含完整代码流程与科研绘图
人工智能·python
砚底藏山河11 小时前
python量化自定义周期 K 线合成
java·开发语言·数据库·python·金融
视觉小萌新11 小时前
AI Class 3 · Chapter 1:变量、字符串、list/dict、if/for(python学习-小白版-有经验可跳过)
python·学习·list
薛定谔的猫-菜鸟程序员12 小时前
软件架构设计师开发资料大全(从入门到精通)
后端·python·系统架构·flask·架构设计师
Ramble_Naylor14 小时前
Rust深度解读:Send 与 Sync 的本质与线程安全边界
python·算法·rust
Allen_LVyingbo14 小时前
NVIDIA CUDA Tile 在医疗计算中的算子形式化、算法重构与内核实现
大数据·python·算法·重构·知识图谱·健康医疗·数据库架构
云和数据.ChenGuang15 小时前
Python 闭包详解:从原理到实战
linux·开发语言·人工智能·python·kubernetes
我命由我1234516 小时前
Python 实用操作 - 文件操作(打开与关闭文件、读取文件、文件写入)
java·开发语言·前端·javascript·数据库·python·java-ee
青少儿编程课堂16 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:倍增法求最近公共祖先LCA解析
c++·python·算法·bfs·信息学竞赛