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()
相关推荐
周周记笔记8 小时前
PyCharm的初始设置
ide·python·pycharm
2401_841495648 小时前
【语音识别】混合高斯模型
人工智能·python·算法·机器学习·语音识别·gmm·混合高斯模型
徐凤年lll9 小时前
python 初学2
开发语言·python
坚持就完事了10 小时前
解析数据练习(小项目)
python
周周记笔记10 小时前
Pycharm详解:高效Python开发的首选IDE
ide·python·pycharm
香辣西红柿炒蛋10 小时前
Python企业编码规范
python
Anson Jiang11 小时前
PyTorch轻松实现CV模型:零基础到实战
pytorch·python·django·flask·python开发
风雨同舟的代码笔记11 小时前
5.Python函数与模块化工程实战:构建高复用代码体系
python
我的xiaodoujiao12 小时前
使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 22--数据驱动--参数化处理 Json 文件
python·学习·测试工具·pytest