Python 中with语句详解和代码示例
·
在 Python 中,with 语句用于简化资源管理(如文件、网络连接、锁等),背后依赖的是上下文管理器协议:即实现了 __enter__() 和 __exit__() 方法的对象。
一、基本概念
with 语句作用:
- 自动调用资源的初始化(进入上下文)
- 自动释放资源(即使发生异常)
基本语法:
with expression as variable:
# 使用资源的代码块
expression是一个返回上下文管理器对象的表达式(必须实现__enter__()和__exit__()方法)。as variable是可选的,用于接收__enter__()的返回值。
背后的机制:
__enter__():当进入with代码块时被调用,其返回值赋给as后的变量。__exit__(exc_type, exc_val, exc_tb):无论with块内是否抛出异常,都会被调用以清理资源。
二、基本示例
示例 1:文件操作(内建实现了上下文管理器)
with open('example.txt', 'r') as f:
data = f.read()
# 不需要显式 f.close(),异常也会自动处理
等价于:
f = open('example.txt', 'r')
try:
data = f.read()
finally:
f.close()
三、自定义上下文管理器(实现 __enter__ / __exit__)
示例 2:自定义资源管理类
class MyContext:
def __enter__(self):
print("Entering context...")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting context...")
if exc_type:
print(f"Handled exception: {exc_value}")
return False # 如果为 True,异常被吞掉;False 表示异常继续传播
# 使用 with
with MyContext() as ctx:
print("Inside with block")
# raise ValueError("Something went wrong") # 可测试异常处理
四、实用场景
示例 3:锁(线程安全)
import threading
lock = threading.Lock()
with lock:
# 线程安全操作
pass
示例 4:数据库事务管理(以 SQLAlchemy 为例)
from sqlalchemy.orm import sessionmaker
Session = sessionmaker()
session = Session()
with session.begin(): # 自动提交或回滚
session.add(some_data)
五、使用 contextlib 快速创建上下文管理器
示例 5:用装饰器实现上下文
from contextlib import contextmanager
@contextmanager
def my_resource():
print("Acquiring resource")
yield "resource"
print("Releasing resource")
with my_resource() as r:
print(f"Using {r}")
六、实际应用场景综合示例
下是针对 文件操作、GPU 资源管理(如 PyTorch)、日志管理 等实际应用场景的 with 语句和上下文管理器实战示例,每一个都结合了 __enter__ / __exit__ 的机制,适用于高质量的 Python 工程开发。
示例一:文件自动写入上下文管理器
class AutoFileWriter:
def __init__(self, filename, mode='w'):
self.filename = filename
self.mode = mode
self.file = None
def __enter__(self):
print(f"[FileWriter] Opening file: {self.filename}")
self.file = open(self.filename, self.mode)
return self.file # 返回给 with 后的变量
def __exit__(self, exc_type, exc_value, traceback):
if self.file:
print(f"[FileWriter] Closing file: {self.filename}")
self.file.close()
if exc_type:
print(f"[FileWriter] Error: {exc_value}")
# 返回 False 让异常继续抛出;True 则吞掉异常
return False
# 使用示例
with AutoFileWriter("output.txt") as f:
f.write("Hello, file context manager!\n")
️ 示例二:PyTorch GPU 自动切换管理器(多 GPU / CPU fallback)
import torch
class DeviceManager:
def __init__(self, prefer_cuda=True):
self.device = torch.device("cuda" if prefer_cuda and torch.cuda.is_available() else "cpu")
def __enter__(self):
print(f"[DeviceManager] Using device: {self.device}")
return self.device # 返回设备对象
def __exit__(self, exc_type, exc_value, traceback):
torch.cuda.empty_cache() # 清除缓存(可选)
print(f"[DeviceManager] Released GPU memory.")
# 使用示例
with DeviceManager() as device:
tensor = torch.randn(1000, 1000).to(device)
result = tensor @ tensor.T
示例三:日志上下文管理器(自动开始与结束记录)
import logging
from datetime import datetime
class LoggingContext:
def __init__(self, section_name):
self.section_name = section_name
def __enter__(self):
self.start_time = datetime.now()
logging.info(f"[{self.section_name}] Start at {self.start_time}")
return self
def __exit__(self, exc_type, exc_val, tb):
end_time = datetime.now()
logging.info(f"[{self.section_name}] End at {end_time}, Duration: {end_time - self.start_time}")
if exc_type:
logging.error(f"[{self.section_name}] Exception: {exc_val}")
return False
# 配置日志
logging.basicConfig(level=logging.INFO, format="%(message)s")
# 使用
with LoggingContext("Training Step"):
# 模拟训练
import time; time.sleep(2)
logging.info("Model training... complete.")
Bonus:多个上下文组合使用(Python 3.10+ 推荐)
with AutoFileWriter("log.txt") as f, DeviceManager() as device:
f.write(f"Computation on device: {device}\n")
t = torch.ones(2, 2).to(device)
f.write(f"Tensor:\n{t}\n")
示例总结说明
| 场景 | 管理器类名 | 资源 | 自动化操作 |
|---|---|---|---|
| 文件 | AutoFileWriter |
文件句柄 | 自动打开 / 关闭文件 |
| GPU | DeviceManager |
torch.device |
自动设备分配 / 清理 CUDA 缓存 |
| 日志记录 | LoggingContext |
日志上下文 | 自动打印开始、结束、异常 |
7、总结
| 方法 | 说明 |
|---|---|
__enter__() |
初始化资源,返回给 as 变量 |
__exit__() |
清理资源,处理异常(3 个参数) |
contextlib |
提供装饰器方式快速创建上下文管理器 |
使用 with 的好处
| 优点 | 描述 |
|---|---|
| 自动资源释放 | 无需手动 close()、release() 等 |
| 异常安全 | 发生异常时也能执行清理代码 |
| 代码更简洁 | 避免冗长的 try/finally 结构 |
| 可扩展 | 可以自定义任意资源管理器 |
更多推荐


所有评论(0)