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 ff 是文件对象,不是 open() 的返回值
    • 你的 MyFileReader__enter__ 返回 self,所以 readerMyFileReader 实例,可调用其方法。
  2. 异常处理
    • 代码块中发生异常时,__exit__ 仍会执行(保证资源释放)
    • __exit__ 返回 True,异常会被静默处理(不抛出);返回 FalseNone,异常会正常抛出
  3. 并非所有对象都能用于 with
    • 必须实现 __enter____exit__ 方法(即「上下文管理器协议」)
    • 常见支持的对象:open()threading.Lockpymysql.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()
相关推荐
zfan52010 分钟前
python对Excel数据处理(1)
python·excel·pandas
小饕15 分钟前
我从零搭建 RAG 学到的 10 件事
python
老歌老听老掉牙20 分钟前
PyQt5+Qt Designer实战:可视化设计智能参数配置界面,告别手动布局时代!
python·qt
格鸰爱童话1 小时前
向AI学习项目技能(六)
java·人工智能·spring boot·python·学习
悟空爬虫-彪哥1 小时前
VRChat开发环境配置,零基础教程
python
数据知道1 小时前
《 Claude Code源码分析与实践》专栏目录
python·ai·github·claude code·claw code
曲幽1 小时前
FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了!
python·vue·upload·fastapi·web·blob·chunk·spark-md5
石工记2 小时前
Agent 应用与图状态编排框架LangGraph
python·ai编程
XiYang-DING2 小时前
【Java】二叉搜索树(BST)
java·开发语言·python
赵优秀一一2 小时前
FastAPI 核心
linux·python·fastapi