在 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 = 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
with MyContext( ) as ctx:
print ( "Inside with block" )
四、实用场景
示例 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
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} " )
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 结构 可扩展 可以自定义任意资源管理器