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()
相关推荐
子夜江寒7 分钟前
基于 OpenCV 的图像形态学与边缘检测
python·opencv·计算机视觉
少林码僧6 小时前
2.31 机器学习神器项目实战:如何在真实项目中应用XGBoost等算法
人工智能·python·算法·机器学习·ai·数据挖掘
智航GIS7 小时前
10.4 Selenium:Web 自动化测试框架
前端·python·selenium·测试工具
jarreyer7 小时前
摄像头相关记录
python
宝贝儿好7 小时前
【强化学习】第六章:无模型控制:在轨MC控制、在轨时序差分学习(Sarsa)、离轨学习(Q-learning)
人工智能·python·深度学习·学习·机器学习·机器人
大、男人7 小时前
python之asynccontextmanager学习
开发语言·python·学习
默默前行的虫虫8 小时前
nicegui文件上传归纳
python
一个没有本领的人8 小时前
UIU-Net运行记录
python
国强_dev8 小时前
Python 的“非直接原因”报错
开发语言·python
副露のmagic8 小时前
更弱智的算法学习 day24
python·学习·算法