python上下文管理器和with
大约 3 分钟
1. 什么是上下文管理器
上下文管理器(Context Manager)是Python中用于管理资源(如文件、数据库连接、锁等)的对象,它定义了在进入和退出代码块时要执行的操作。上下文管理器通过实现 __enter__() 和 __exit__() 方法来工作
2. with的作用
with语句提供了一种优雅的方式来管理资源,确保资源被正确初始化和清理,即使在发生异常的情况下也是如此。它的主要优势包括:
- 自动资源管理:自动获取和释放资源
- 异常安全:即使在
with块内发生异常,清理代码也会被执行 - 代码简洁:避免了冗长的
try...finally块 - 可读性强:清晰地标出了资源的作用范围
with的工作原理:
- 调用上下文管理器的
__enter__()方法 - 将
__enter__()的返回值赋值给as后面的变量 - 执行with块内的代码
- 无论块内代码是否发生异常,都会调用
__exit__()方法进行清理
自定义上下文管理器类
# 自定义上下文管理器 - 类方式
class Timer:
"""测量代码执行时间的上下文管理器"""
def __init__(self, name="Operation"):
self.name = name
def __enter__(self):
import time
self.start = time.time()
print(f"开始: {self.name}")
return self # 这个返回值会赋值给as后面的变量
def __exit__(self, exc_type, exc_value, traceback):
import time
self.end = time.time()
self.duration = self.end - self.start
print(f"⏰ 结束: {self.name}, 耗时: {self.duration:.4f}秒")
# 返回False让异常继续传播,返回True则抑制异常
return False
# 使用自定义的Timer上下文管理器
def expensive_operation():
with Timer("昂贵的计算"):
import time
time.sleep(1) # 模拟耗时操作
result = sum(i * i for i in range(10000))
return result
contextlib
from contextlib import contextmanager
@contextmanager
def temporary_change(obj, attr, new_value):
"""临时修改对象属性的上下文管理器"""
original_value = getattr(obj, attr)
setattr(obj, attr, new_value)
try:
yield # 这里是将控制权交给with块的地方
finally:
# 无论是否发生异常,都恢复原始值
setattr(obj, attr, original_value)
class Config:
debug_mode = False
# 使用临时修改的上下文管理器
def test_debug_functionality():
config = Config()
print(f"修改前: debug_mode = {config.debug_mode}")
with temporary_change(config, 'debug_mode', True):
print(f"在with块内: debug_mode = {config.debug_mode}")
# 这里可以测试debug模式下的功能
print(f"修改后: debug_mode = {config.debug_mode}") # 自动恢复
3. 什么时候应该使用上下文管理器?
主要在这些场景下使用:
- 资源管理:文件、网络连接、数据库连接等需要关闭的资源
- 锁的获取和释放:确保线程安全
- 事务管理:数据库事务的开始、提交和回滚
- 临时状态修改:需要临时改变某些设置,之后自动恢复
- 计时和性能分析:测量代码块的执行时间
4. contextlib.contextmanager装饰器是如何工作的?
这个装饰器将生成器函数转换为上下文管理器。生成器必须只yield一次:
- yield之前的代码相当于
__enter__()方法 - yield的值相当于
__enter__()的返回值 - yield之后的代码相当于
__exit__()方法,放在finally块中确保执行