023-上下文管理器
🔴 难度: 高级 | ⏱️ 预计时间: 4小时 | 📋 前置: 022-生成器与迭代器
学习目标
完成本章节后,你将能够:
- 理解上下文管理器的概念和作用
- 掌握
with语句的使用方法 - 实现自定义上下文管理器
- 使用
contextlib模块简化上下文管理器的创建 - 应用上下文管理器解决资源管理问题
- 设计复杂的上下文管理器系统
上下文管理器基础
什么是上下文管理器
上下文管理器是一个定义了在with语句中使用的运行时上下文的对象。它负责执行进入和退出所需的操作,确保资源的正确获取和释放。
# 上下文管理器基础概念
print("=== 上下文管理器基础概念 ===")
# 最常见的上下文管理器:文件操作
print("\n1. 文件操作上下文管理器:")
# 传统方式(容易出错)
print("传统方式:")
try:
file = open('example.txt', 'w')
file.write('Hello, World!')
finally:
file.close() # 必须手动关闭
# 使用with语句(推荐)
print("\nwith语句方式:")
with open('example.txt', 'w') as file:
file.write('Hello, World!') # 自动关闭文件
print("文件已自动关闭")
# 验证文件是否关闭
print(f"文件是否关闭: {file.closed}")
# 多个上下文管理器
print("\n2. 多个上下文管理器:")
with open('input.txt', 'w') as input_file, open('output.txt', 'w') as output_file:
input_file.write('输入数据')
output_file.write('输出数据')
print("两个文件都会自动关闭")
# 嵌套上下文管理器
print("\n3. 嵌套上下文管理器:")
with open('outer.txt', 'w') as outer_file:
outer_file.write('外层文件\n')
with open('inner.txt', 'w') as inner_file:
inner_file.write('内层文件\n')
print("嵌套文件操作")
print("内层文件已关闭")
print("外层文件已关闭")
上下文管理器协议
上下文管理器协议定义了两个特殊方法:__enter__和__exit__。
# 上下文管理器协议
print("\n=== 上下文管理器协议 ===")
class SimpleContextManager:
"""简单的上下文管理器示例"""
def __init__(self, name):
self.name = name
print(f"初始化上下文管理器: {self.name}")
def __enter__(self):
"""进入上下文时调用"""
print(f"进入上下文: {self.name}")
return self # 返回值会赋给as后的变量
def __exit__(self, exc_type, exc_value, traceback):
"""退出上下文时调用"""
print(f"退出上下文: {self.name}")
if exc_type is not None:
print(f"异常类型: {exc_type.__name__}")
print(f"异常值: {exc_value}")
print(f"异常追踪: {traceback}")
return False # 不抑制异常
return True
def do_something(self):
print(f"在上下文中执行操作: {self.name}")
# 使用自定义上下文管理器
print("\n1. 正常使用:")
with SimpleContextManager("测试管理器") as manager:
manager.do_something()
print("\n2. 异常情况:")
try:
with SimpleContextManager("异常测试") as manager:
manager.do_something()
raise ValueError("测试异常")
except ValueError as e:
print(f"捕获异常: {e}")
print("\n3. 多个上下文管理器:")
with SimpleContextManager("第一个") as first, SimpleContextManager("第二个") as second:
first.do_something()
second.do_something()
上下文管理器的执行流程
# 上下文管理器执行流程详解
print("\n=== 上下文管理器执行流程 ===")
class DetailedContextManager:
"""详细展示执行流程的上下文管理器"""
def __init__(self, name):
self.name = name
print(f"步骤1: 创建对象 {self.name}")
def __enter__(self):
print(f"步骤2: 调用 __enter__ 方法 ({self.name})")
print(f"步骤3: 获取资源 ({self.name})")
return f"资源_{self.name}"
def __exit__(self, exc_type, exc_value, traceback):
print(f"步骤6: 调用 __exit__ 方法 ({self.name})")
print(f"步骤7: 释放资源 ({self.name})")
if exc_type:
print(f"步骤8: 处理异常 {exc_type.__name__}: {exc_value}")
# 返回True表示抑制异常,False表示不抑制
return False
print(f"步骤8: 正常退出 ({self.name})")
return True
print("\n执行流程演示:")
with DetailedContextManager("流程演示") as resource:
print(f"步骤4: 进入with代码块,resource = {resource}")
print(f"步骤5: 执行with代码块中的代码")
# 这里是with代码块的内容
pass
print("\n异常处理流程:")
try:
with DetailedContextManager("异常流程") as resource:
print(f"步骤4: 进入with代码块,resource = {resource}")
print(f"步骤5: 执行代码并抛出异常")
raise RuntimeError("模拟异常")
except RuntimeError as e:
print(f"步骤9: 在外部捕获异常: {e}")
实用的上下文管理器
资源管理上下文管理器
# 实用的资源管理上下文管理器
print("\n=== 资源管理上下文管理器 ===")
import time
import threading
from typing import Optional, Any
class TimerContext:
"""计时上下文管理器"""
def __init__(self, name: str = "操作"):
self.name = name
self.start_time: Optional[float] = None
self.end_time: Optional[float] = None
def __enter__(self):
print(f"开始计时: {self.name}")
self.start_time = time.time()
return self
def __exit__(self, exc_type, exc_value, traceback):
self.end_time = time.time()
duration = self.end_time - self.start_time
print(f"结束计时: {self.name}, 耗时: {duration:.4f}秒")
return False
@property
def duration(self) -> float:
"""获取执行时间"""
if self.start_time and self.end_time:
return self.end_time - self.start_time
return 0.0
class LockContext:
"""锁管理上下文管理器"""
def __init__(self, lock: threading.Lock, timeout: float = 5.0):
self.lock = lock
self.timeout = timeout
self.acquired = False
def __enter__(self):
print(f"尝试获取锁,超时时间: {self.timeout}秒")
self.acquired = self.lock.acquire(timeout=self.timeout)
if not self.acquired:
raise TimeoutError(f"无法在{self.timeout}秒内获取锁")
print("成功获取锁")
return self
def __exit__(self, exc_type, exc_value, traceback):
if self.acquired:
self.lock.release()
print("释放锁")
return False
class DatabaseConnection:
"""模拟数据库连接上下文管理器"""
def __init__(self, connection_string: str):
self.connection_string = connection_string
self.connection = None
self.transaction_active = False
def __enter__(self):
print(f"连接数据库: {self.connection_string}")
# 模拟连接过程
self.connection = f"Connection_{id(self)}"
print(f"数据库连接成功: {self.connection}")
return self
def __exit__(self, exc_type, exc_value, traceback):
if self.transaction_active:
if exc_type:
print("检测到异常,回滚事务")
self.rollback()
else:
print("正常退出,提交事务")
self.commit()
print(f"关闭数据库连接: {self.connection}")
self.connection = None
return False
def begin_transaction(self):
"""开始事务"""
print("开始事务")
self.transaction_active = True
def commit(self):
"""提交事务"""
print("提交事务")
self.transaction_active = False
def rollback(self):
"""回滚事务"""
print("回滚事务")
self.transaction_active = False
def execute(self, sql: str):
"""执行SQL"""
print(f"执行SQL: {sql}")
return f"Result of {sql}"
# 演示资源管理上下文管理器
print("\n1. 计时上下文管理器:")
with TimerContext("数据处理") as timer:
# 模拟一些耗时操作
time.sleep(0.1)
print("正在处理数据...")
time.sleep(0.1)
print(f"总耗时: {timer.duration:.4f}秒")
print("\n2. 锁管理上下文管理器:")
lock = threading.Lock()
with LockContext(lock, timeout=2.0):
print("在锁保护下执行关键代码")
time.sleep(0.1)
print("\n3. 数据库连接上下文管理器:")
# 正常情况
with DatabaseConnection("postgresql://localhost:5432/mydb") as db:
db.begin_transaction()
db.execute("INSERT INTO users (name) VALUES ('Alice')")
db.execute("UPDATE users SET age = 25 WHERE name = 'Alice'")
print("\n异常情况:")
try:
with DatabaseConnection("postgresql://localhost:5432/mydb") as db:
db.begin_transaction()
db.execute("INSERT INTO users (name) VALUES ('Bob')")
raise ValueError("模拟数据库操作异常")
except ValueError as e:
print(f"捕获异常: {e}")
状态管理上下文管理器
# 状态管理上下文管理器
print("\n=== 状态管理上下文管理器 ===")
import os
import sys
from typing import Dict, Any
class EnvironmentContext:
"""环境变量管理上下文管理器"""
def __init__(self, **env_vars):
self.env_vars = env_vars
self.original_values = {}
def __enter__(self):
print(f"设置环境变量: {self.env_vars}")
# 保存原始值
for key in self.env_vars:
self.original_values[key] = os.environ.get(key)
# 设置新值
for key, value in self.env_vars.items():
os.environ[key] = str(value)
return self
def __exit__(self, exc_type, exc_value, traceback):
print("恢复环境变量")
# 恢复原始值
for key, original_value in self.original_values.items():
if original_value is None:
os.environ.pop(key, None)
else:
os.environ[key] = original_value
return False
class WorkingDirectoryContext:
"""工作目录管理上下文管理器"""
def __init__(self, new_dir: str):
self.new_dir = new_dir
self.original_dir = None
def __enter__(self):
self.original_dir = os.getcwd()
print(f"切换工作目录: {self.original_dir} -> {self.new_dir}")
# 创建目录(如果不存在)
os.makedirs(self.new_dir, exist_ok=True)
os.chdir(self.new_dir)
return self
def __exit__(self, exc_type, exc_value, traceback):
print(f"恢复工作目录: {self.new_dir} -> {self.original_dir}")
os.chdir(self.original_dir)
return False
class AttributeContext:
"""对象属性临时修改上下文管理器"""
def __init__(self, obj: Any, **attrs):
self.obj = obj
self.new_attrs = attrs
self.original_attrs = {}
def __enter__(self):
print(f"临时修改对象属性: {self.new_attrs}")
# 保存原始属性值
for attr_name in self.new_attrs:
if hasattr(self.obj, attr_name):
self.original_attrs[attr_name] = getattr(self.obj, attr_name)
else:
self.original_attrs[attr_name] = AttributeError(f"属性 {attr_name} 不存在")
# 设置新属性值
for attr_name, attr_value in self.new_attrs.items():
setattr(self.obj, attr_name, attr_value)
return self.obj
def __exit__(self, exc_type, exc_value, traceback):
print("恢复对象属性")
# 恢复原始属性值
for attr_name, original_value in self.original_attrs.items():
if isinstance(original_value, AttributeError):
delattr(self.obj, attr_name)
else:
setattr(self.obj, attr_name, original_value)
return False
class ConfigContext:
"""配置管理上下文管理器"""
def __init__(self, config_dict: Dict[str, Any], **config_updates):
self.config = config_dict
self.updates = config_updates
self.backup = {}
def __enter__(self):
print(f"临时更新配置: {self.updates}")
# 备份原始配置
for key in self.updates:
if key in self.config:
self.backup[key] = self.config[key]
else:
self.backup[key] = KeyError(f"配置项 {key} 不存在")
# 应用更新
self.config.update(self.updates)
return self.config
def __exit__(self, exc_type, exc_value, traceback):
print("恢复原始配置")
# 恢复配置
for key, original_value in self.backup.items():
if isinstance(original_value, KeyError):
self.config.pop(key, None)
else:
self.config[key] = original_value
return False
# 演示状态管理上下文管理器
print("\n1. 环境变量管理:")
print(f"原始PATH长度: {len(os.environ.get('PATH', ''))}")
with EnvironmentContext(TEST_VAR="测试值", PATH="/custom/path"):
print(f"临时TEST_VAR: {os.environ.get('TEST_VAR')}")
print(f"临时PATH: {os.environ.get('PATH')}")
print(f"恢复后PATH长度: {len(os.environ.get('PATH', ''))}")
print(f"恢复后TEST_VAR: {os.environ.get('TEST_VAR', '不存在')}")
print("\n2. 工作目录管理:")
print(f"当前目录: {os.getcwd()}")
with WorkingDirectoryContext("/tmp/test_context"):
print(f"临时目录: {os.getcwd()}")
# 在临时目录中创建文件
with open("temp_file.txt", "w") as f:
f.write("临时文件内容")
print(f"恢复目录: {os.getcwd()}")
print("\n3. 对象属性管理:")
class TestObject:
def __init__(self):
self.value = 100
self.name = "原始名称"
test_obj = TestObject()
print(f"原始属性: value={test_obj.value}, name={test_obj.name}")
with AttributeContext(test_obj, value=200, name="临时名称", new_attr="新属性") as obj:
print(f"临时属性: value={obj.value}, name={obj.name}, new_attr={obj.new_attr}")
print(f"恢复属性: value={test_obj.value}, name={test_obj.name}")
print(f"new_attr存在: {hasattr(test_obj, 'new_attr')}")
print("\n4. 配置管理:")
app_config = {
"debug": False,
"database_url": "postgresql://prod",
"cache_size": 1000
}
print(f"原始配置: {app_config}")
with ConfigContext(app_config, debug=True, database_url="sqlite://test", new_setting="测试") as config:
print(f"临时配置: {config}")
print(f"恢复配置: {app_config}")
contextlib模块
使用contextlib简化上下文管理器
# 使用contextlib模块
print("\n=== contextlib模块 ===")
import contextlib
from contextlib import contextmanager, ExitStack, suppress, redirect_stdout, redirect_stderr
from io import StringIO
import tempfile
import shutil
# 1. @contextmanager装饰器
print("\n1. @contextmanager装饰器:")
@contextmanager
def simple_timer(name):
"""使用生成器创建上下文管理器"""
import time
print(f"开始计时: {name}")
start_time = time.time()
try:
yield start_time # yield前的代码相当于__enter__
finally:
# yield后的代码相当于__exit__
end_time = time.time()
print(f"结束计时: {name}, 耗时: {end_time - start_time:.4f}秒")
@contextmanager
def temporary_attribute(obj, attr_name, temp_value):
"""临时修改对象属性"""
original_value = getattr(obj, attr_name, None)
has_attr = hasattr(obj, attr_name)
print(f"设置临时属性 {attr_name} = {temp_value}")
setattr(obj, attr_name, temp_value)
try:
yield obj
finally:
if has_attr:
setattr(obj, attr_name, original_value)
print(f"恢复属性 {attr_name} = {original_value}")
else:
delattr(obj, attr_name)
print(f"删除临时属性 {attr_name}")
@contextmanager
def database_transaction():
"""数据库事务上下文管理器"""
print("开始事务")
transaction_id = f"txn_{id(object())}"
try:
yield transaction_id
print(f"提交事务: {transaction_id}")
except Exception as e:
print(f"回滚事务: {transaction_id}, 原因: {e}")
raise
# 使用@contextmanager创建的上下文管理器
with simple_timer("测试操作"):
time.sleep(0.1)
print("执行一些操作")
class TestObj:
def __init__(self):
self.value = 42
test_obj = TestObj()
print(f"\n原始值: {test_obj.value}")
with temporary_attribute(test_obj, "value", 100) as obj:
print(f"临时值: {obj.value}")
print(f"恢复值: {test_obj.value}")
print("\n数据库事务演示:")
try:
with database_transaction() as txn_id:
print(f"在事务 {txn_id} 中执行操作")
# raise ValueError("模拟错误") # 取消注释测试回滚
except ValueError as e:
print(f"处理异常: {e}")
contextlib的实用工具
# contextlib实用工具
print("\n=== contextlib实用工具 ===")
# 2. ExitStack - 动态管理多个上下文管理器
print("\n2. ExitStack:")
def process_files(filenames):
"""使用ExitStack处理多个文件"""
with ExitStack() as stack:
files = []
for filename in filenames:
# 动态添加上下文管理器
file_obj = stack.enter_context(open(filename, 'w'))
files.append(file_obj)
# 所有文件都已打开,现在可以使用它们
for i, file_obj in enumerate(files):
file_obj.write(f"这是文件 {i+1} 的内容\n")
print(f"成功处理了 {len(files)} 个文件")
return files
# 所有文件在这里自动关闭
# 创建测试文件
test_files = ['test1.txt', 'test2.txt', 'test3.txt']
process_files(test_files)
# 验证文件已关闭
with open('test1.txt', 'r') as f:
print(f"文件内容: {f.read().strip()}")
# 3. suppress - 抑制指定异常
print("\n3. suppress:")
with suppress(FileNotFoundError):
os.remove('不存在的文件.txt')
print("这行不会执行")
print("FileNotFoundError被抑制了")
with suppress(ValueError, TypeError):
int('不是数字')
print("这行不会执行")
print("ValueError被抑制了")
# 4. redirect_stdout和redirect_stderr
print("\n4. 重定向标准输出:")
output_buffer = StringIO()
with redirect_stdout(output_buffer):
print("这个输出被重定向了")
print("这也是")
print(f"捕获的输出: {repr(output_buffer.getvalue())}")
# 重定向到文件
with open('output.txt', 'w') as f:
with redirect_stdout(f):
print("这个输出写入文件")
print("数字:", 42)
with open('output.txt', 'r') as f:
print(f"文件内容: {repr(f.read())}")
# 5. 组合使用多个contextlib工具
print("\n5. 组合使用:")
@contextmanager
def capture_and_suppress():
"""捕获输出并抑制异常"""
output = StringIO()
with ExitStack() as stack:
stack.enter_context(redirect_stdout(output))
stack.enter_context(suppress(ValueError, TypeError))
try:
yield output
finally:
pass
with capture_and_suppress() as output:
print("正常输出")
int('错误输入') # 这个异常会被抑制
print("继续输出")
print(f"捕获的输出: {repr(output.getvalue())}")
# 6. 临时目录管理
print("\n6. 临时目录管理:")
@contextmanager
def temporary_directory():
"""创建临时目录"""
temp_dir = tempfile.mkdtemp()
print(f"创建临时目录: {temp_dir}")
try:
yield temp_dir
finally:
shutil.rmtree(temp_dir)
print(f"删除临时目录: {temp_dir}")
with temporary_directory() as temp_dir:
# 在临时目录中工作
temp_file = os.path.join(temp_dir, 'temp.txt')
with open(temp_file, 'w') as f:
f.write('临时文件内容')
print(f"创建临时文件: {temp_file}")
# 验证文件存在
print(f"文件存在: {os.path.exists(temp_file)}")
# 临时目录已被删除
print(f"临时目录已删除")
高级contextlib应用
# 高级contextlib应用
print("\n=== 高级contextlib应用 ===")
from contextlib import asynccontextmanager, nullcontext
import asyncio
from typing import Optional, Union
# 1. 条件上下文管理器
print("\n1. 条件上下文管理器:")
@contextmanager
def conditional_context(condition, context_manager):
"""根据条件决定是否使用上下文管理器"""
if condition:
with context_manager as value:
yield value
else:
yield None
# 使用条件上下文管理器
for use_timer in [True, False]:
print(f"\n使用计时器: {use_timer}")
with conditional_context(use_timer, simple_timer("条件计时")) as timer:
time.sleep(0.05)
if timer:
print("计时器已启用")
else:
print("计时器未启用")
# 2. 嵌套上下文管理器工厂
print("\n2. 嵌套上下文管理器:")
@contextmanager
def nested_contexts(*context_managers):
"""嵌套多个上下文管理器"""
with ExitStack() as stack:
results = []
for cm in context_managers:
result = stack.enter_context(cm)
results.append(result)
yield results
# 使用嵌套上下文管理器
with nested_contexts(
simple_timer("操作1"),
simple_timer("操作2"),
temporary_directory()
) as (timer1, timer2, temp_dir):
print(f"在嵌套上下文中工作")
print(f"临时目录: {temp_dir}")
time.sleep(0.1)
# 3. 资源池上下文管理器
print("\n3. 资源池管理:")
class ResourcePool:
"""资源池"""
def __init__(self, create_resource, max_size=5):
self.create_resource = create_resource
self.max_size = max_size
self.pool = []
self.in_use = set()
@contextmanager
def get_resource(self):
"""获取资源的上下文管理器"""
# 尝试从池中获取资源
if self.pool:
resource = self.pool.pop()
else:
resource = self.create_resource()
self.in_use.add(resource)
print(f"获取资源: {resource}")
try:
yield resource
finally:
# 归还资源到池中
self.in_use.remove(resource)
if len(self.pool) < self.max_size:
self.pool.append(resource)
print(f"归还资源到池: {resource}")
else:
print(f"池已满,销毁资源: {resource}")
# 创建资源池
def create_connection():
return f"Connection_{id(object())}"
connection_pool = ResourcePool(create_connection, max_size=2)
# 使用资源池
print("\n使用资源池:")
with connection_pool.get_resource() as conn1:
print(f"使用连接1: {conn1}")
with connection_pool.get_resource() as conn2:
print(f"使用连接2: {conn2}")
with connection_pool.get_resource() as conn3:
print(f"使用连接3: {conn3}")
print(f"池中剩余资源: {len(connection_pool.pool)}")
# 4. 异步上下文管理器(Python 3.7+)
print("\n4. 异步上下文管理器:")
# 注意:这里只是展示语法,实际运行需要异步环境
class AsyncContextExample:
"""异步上下文管理器示例"""
async def __aenter__(self):
print("异步进入上下文")
# 模拟异步操作
await asyncio.sleep(0.01)
return self
async def __aexit__(self, exc_type, exc_value, traceback):
print("异步退出上下文")
# 模拟异步清理
await asyncio.sleep(0.01)
return False
@asynccontextmanager
async def async_timer(name):
"""异步计时器"""
print(f"异步开始计时: {name}")
start_time = time.time()
try:
yield start_time
finally:
end_time = time.time()
print(f"异步结束计时: {name}, 耗时: {end_time - start_time:.4f}秒")
# 异步上下文管理器的使用示例(需要在异步函数中)
async def async_example():
async with AsyncContextExample():
print("在异步上下文中")
await asyncio.sleep(0.05)
async with async_timer("异步操作"):
print("执行异步操作")
await asyncio.sleep(0.1)
# 运行异步示例
print("运行异步上下文管理器示例:")
asyncio.run(async_example())
# 5. nullcontext - 空上下文管理器
print("\n5. nullcontext:")
def process_with_optional_context(use_context=True):
"""可选地使用上下文管理器"""
context = simple_timer("可选计时") if use_context else nullcontext()
with context:
print("执行处理逻辑")
time.sleep(0.05)
print("使用上下文:")
process_with_optional_context(True)
print("\n不使用上下文:")
process_with_optional_context(False)
高级上下文管理器模式
装饰器形式的上下文管理器
# 装饰器形式的上下文管理器
print("\n=== 装饰器形式的上下文管理器 ===")
import functools
from typing import Callable, Any
class ContextDecorator:
"""可以作为装饰器使用的上下文管理器基类"""
def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
with self:
return func(*args, **kwargs)
return wrapper
class TimingContext(ContextDecorator):
"""计时上下文管理器(可作为装饰器)"""
def __init__(self, name: str = "操作"):
self.name = name
self.duration = 0
def __enter__(self):
print(f"开始计时: {self.name}")
self.start_time = time.time()
return self
def __exit__(self, exc_type, exc_value, traceback):
end_time = time.time()
self.duration = end_time - self.start_time
print(f"结束计时: {self.name}, 耗时: {self.duration:.4f}秒")
return False
class LoggingContext(ContextDecorator):
"""日志上下文管理器"""
def __init__(self, operation: str, level: str = "INFO"):
self.operation = operation
self.level = level
def __enter__(self):
print(f"[{self.level}] 开始操作: {self.operation}")
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type:
print(f"[ERROR] 操作失败: {self.operation}, 异常: {exc_value}")
else:
print(f"[{self.level}] 操作完成: {self.operation}")
return False
class RetryContext(ContextDecorator):
"""重试上下文管理器"""
def __init__(self, max_retries: int = 3, delay: float = 1.0):
self.max_retries = max_retries
self.delay = delay
self.attempt = 0
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type and self.attempt < self.max_retries:
self.attempt += 1
print(f"操作失败,第{self.attempt}次重试 (最多{self.max_retries}次)")
time.sleep(self.delay)
return True # 抑制异常,继续重试
if exc_type:
print(f"操作最终失败,已重试{self.attempt}次")
return False
# 1. 作为上下文管理器使用
print("\n1. 作为上下文管理器使用:")
with TimingContext("数据处理"):
time.sleep(0.1)
print("处理数据中...")
with LoggingContext("文件操作", "DEBUG"):
print("执行文件操作")
# 2. 作为装饰器使用
print("\n2. 作为装饰器使用:")
@TimingContext("函数执行")
@LoggingContext("业务逻辑")
def business_function(x, y):
"""业务函数"""
print(f"执行业务逻辑: {x} + {y}")
time.sleep(0.05)
return x + y
result = business_function(10, 20)
print(f"结果: {result}")
# 3. 重试装饰器
print("\n3. 重试机制:")
@RetryContext(max_retries=2, delay=0.1)
def unreliable_operation():
"""不可靠的操作"""
import random
if random.random() < 0.7: # 70%的概率失败
raise RuntimeError("操作失败")
print("操作成功!")
return "成功结果"
try:
result = unreliable_operation()
print(f"最终结果: {result}")
except RuntimeError as e:
print(f"操作彻底失败: {e}")
上下文管理器链
# 上下文管理器链
print("\n=== 上下文管理器链 ===")
class ContextChain:
"""上下文管理器链"""
def __init__(self, *contexts):
self.contexts = contexts
self.entered_contexts = []
def __enter__(self):
results = []
try:
for context in self.contexts:
result = context.__enter__()
self.entered_contexts.append(context)
results.append(result)
return results
except Exception:
# 如果有异常,需要清理已经进入的上下文
self._cleanup()
raise
def __exit__(self, exc_type, exc_value, traceback):
return self._cleanup(exc_type, exc_value, traceback)
def _cleanup(self, exc_type=None, exc_value=None, traceback=None):
# 按相反顺序退出上下文
exceptions = []
for context in reversed(self.entered_contexts):
try:
context.__exit__(exc_type, exc_value, traceback)
except Exception as e:
exceptions.append(e)
self.entered_contexts.clear()
# 如果有多个异常,抛出第一个
if exceptions:
raise exceptions[0]
return False
class ConditionalContext:
"""条件上下文管理器"""
def __init__(self, condition, true_context, false_context=None):
self.condition = condition
self.true_context = true_context
self.false_context = false_context or nullcontext()
self.active_context = None
def __enter__(self):
self.active_context = self.true_context if self.condition else self.false_context
return self.active_context.__enter__()
def __exit__(self, exc_type, exc_value, traceback):
if self.active_context:
return self.active_context.__exit__(exc_type, exc_value, traceback)
return False
class CachedContext:
"""缓存上下文管理器"""
def __init__(self, cache_key, context_factory):
self.cache_key = cache_key
self.context_factory = context_factory
self._cache = {}
def __enter__(self):
if self.cache_key not in self._cache:
context = self.context_factory()
self._cache[self.cache_key] = context
print(f"创建新的上下文: {self.cache_key}")
else:
context = self._cache[self.cache_key]
print(f"使用缓存的上下文: {self.cache_key}")
return context.__enter__()
def __exit__(self, exc_type, exc_value, traceback):
context = self._cache.get(self.cache_key)
if context:
return context.__exit__(exc_type, exc_value, traceback)
return False
# 演示上下文管理器链
print("\n1. 上下文管理器链:")
context1 = TimingContext("操作1")
context2 = LoggingContext("操作2")
context3 = simple_timer("操作3")
with ContextChain(context1, context2, context3) as results:
print(f"链中的上下文结果: {len(results)}")
time.sleep(0.1)
print("在链式上下文中执行操作")
print("\n2. 条件上下文管理器:")
for debug_mode in [True, False]:
print(f"\n调试模式: {debug_mode}")
with ConditionalContext(
debug_mode,
LoggingContext("调试操作", "DEBUG"),
LoggingContext("生产操作", "INFO")
):
print("执行条件相关的操作")
print("\n3. 缓存上下文管理器:")
def create_expensive_context():
print("创建昂贵的上下文...")
return TimingContext("昂贵操作")
# 第一次使用
with CachedContext("expensive", create_expensive_context):
time.sleep(0.05)
print("第一次使用")
# 第二次使用(应该使用缓存)
with CachedContext("expensive", create_expensive_context):
time.sleep(0.05)
print("第二次使用")
异步上下文管理器进阶
# 异步上下文管理器进阶
print("\n=== 异步上下文管理器进阶 ===")
import asyncio
from contextlib import asynccontextmanager
from typing import AsyncGenerator
class AsyncResourceManager:
"""异步资源管理器"""
def __init__(self, resource_name: str):
self.resource_name = resource_name
self.resource = None
async def __aenter__(self):
print(f"异步获取资源: {self.resource_name}")
# 模拟异步资源获取
await asyncio.sleep(0.01)
self.resource = f"Resource_{self.resource_name}_{id(self)}"
print(f"资源获取成功: {self.resource}")
return self.resource
async def __aexit__(self, exc_type, exc_value, traceback):
print(f"异步释放资源: {self.resource}")
# 模拟异步资源释放
await asyncio.sleep(0.01)
self.resource = None
print("资源释放完成")
return False
@asynccontextmanager
async def async_database_transaction():
"""异步数据库事务"""
transaction_id = f"async_txn_{id(object())}"
print(f"开始异步事务: {transaction_id}")
try:
# 模拟事务开始
await asyncio.sleep(0.01)
yield transaction_id
# 模拟事务提交
await asyncio.sleep(0.01)
print(f"提交异步事务: {transaction_id}")
except Exception as e:
# 模拟事务回滚
await asyncio.sleep(0.01)
print(f"回滚异步事务: {transaction_id}, 原因: {e}")
raise
@asynccontextmanager
async def async_connection_pool(max_connections: int = 5):
"""异步连接池"""
pool = []
active_connections = set()
async def get_connection():
if pool:
conn = pool.pop()
else:
# 模拟创建新连接
await asyncio.sleep(0.01)
conn = f"AsyncConn_{len(active_connections)}"
active_connections.add(conn)
return conn
async def return_connection(conn):
active_connections.remove(conn)
if len(pool) < max_connections:
pool.append(conn)
print(f"初始化异步连接池,最大连接数: {max_connections}")
try:
yield get_connection, return_connection
finally:
print(f"关闭异步连接池,活跃连接: {len(active_connections)}")
# 清理所有连接
for conn in active_connections:
print(f"强制关闭连接: {conn}")
async def async_context_examples():
"""异步上下文管理器示例"""
print("\n1. 基本异步上下文管理器:")
async with AsyncResourceManager("数据库") as resource:
print(f"使用资源: {resource}")
await asyncio.sleep(0.05)
print("\n2. 异步事务管理:")
try:
async with async_database_transaction() as txn:
print(f"在事务 {txn} 中执行操作")
await asyncio.sleep(0.02)
# raise ValueError("模拟事务错误") # 取消注释测试回滚
except ValueError as e:
print(f"处理事务异常: {e}")
print("\n3. 异步连接池:")
async with async_connection_pool(3) as (get_conn, return_conn):
# 获取多个连接
conn1 = await get_conn()
conn2 = await get_conn()
print(f"获取连接: {conn1}, {conn2}")
# 使用连接
await asyncio.sleep(0.02)
# 归还连接
await return_conn(conn1)
await return_conn(conn2)
print("连接已归还")
print("\n4. 并发异步上下文:")
async def worker(worker_id):
async with AsyncResourceManager(f"Worker{worker_id}") as resource:
print(f"Worker {worker_id} 开始工作")
await asyncio.sleep(0.1)
print(f"Worker {worker_id} 完成工作")
return f"Result_{worker_id}"
# 并发执行多个异步上下文
tasks = [worker(i) for i in range(3)]
results = await asyncio.gather(*tasks)
print(f"并发结果: {results}")
# 运行异步示例
print("运行异步上下文管理器示例:")
asyncio.run(async_context_examples())
实践练习
练习1:配置管理系统
创建一个完整的配置管理系统,支持多层配置、环境变量、配置验证等功能。
# 练习1:配置管理系统
print("\n=== 练习1:配置管理系统 ===")
import json
import os
from typing import Dict, Any, Optional, Union
from contextlib import contextmanager
from copy import deepcopy
class ConfigurationError(Exception):
"""配置错误异常"""
pass
class ConfigValidator:
"""配置验证器"""
@staticmethod
def validate_database_config(config: Dict[str, Any]) -> bool:
"""验证数据库配置"""
required_fields = ['host', 'port', 'database', 'username']
for field in required_fields:
if field not in config:
raise ConfigurationError(f"数据库配置缺少必需字段: {field}")
if not isinstance(config['port'], int) or config['port'] <= 0:
raise ConfigurationError("数据库端口必须是正整数")
return True
@staticmethod
def validate_logging_config(config: Dict[str, Any]) -> bool:
"""验证日志配置"""
valid_levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
level = config.get('level', 'INFO')
if level not in valid_levels:
raise ConfigurationError(f"无效的日志级别: {level}")
return True
class ConfigManager:
"""配置管理器"""
def __init__(self):
self.config_stack = []
self.validators = {
'database': ConfigValidator.validate_database_config,
'logging': ConfigValidator.validate_logging_config
}
def load_from_file(self, filename: str) -> Dict[str, Any]:
"""从文件加载配置"""
try:
with open(filename, 'r', encoding='utf-8') as f:
if filename.endswith('.json'):
return json.load(f)
else:
# 简单的key=value格式
config = {}
for line in f:
line = line.strip()
if line and not line.startswith('#'):
key, value = line.split('=', 1)
config[key.strip()] = value.strip()
return config
except FileNotFoundError:
print(f"配置文件不存在: {filename}")
return {}
except Exception as e:
raise ConfigurationError(f"加载配置文件失败: {e}")
def load_from_env(self, prefix: str = 'APP_') -> Dict[str, Any]:
"""从环境变量加载配置"""
config = {}
for key, value in os.environ.items():
if key.startswith(prefix):
config_key = key[len(prefix):].lower()
# 尝试转换数据类型
if value.isdigit():
config[config_key] = int(value)
elif value.lower() in ('true', 'false'):
config[config_key] = value.lower() == 'true'
else:
config[config_key] = value
return config
def merge_configs(self, *configs: Dict[str, Any]) -> Dict[str, Any]:
"""合并多个配置"""
merged = {}
for config in configs:
self._deep_merge(merged, config)
return merged
def _deep_merge(self, target: Dict[str, Any], source: Dict[str, Any]):
"""深度合并字典"""
for key, value in source.items():
if key in target and isinstance(target[key], dict) and isinstance(value, dict):
self._deep_merge(target[key], value)
else:
target[key] = value
def validate_config(self, config: Dict[str, Any]):
"""验证配置"""
for section, validator in self.validators.items():
if section in config:
try:
validator(config[section])
except ConfigurationError as e:
raise ConfigurationError(f"配置验证失败 [{section}]: {e}")
@contextmanager
def config_context(self, **config_overrides):
"""配置上下文管理器"""
# 获取当前配置
current_config = self.get_current_config()
# 应用覆盖配置
new_config = deepcopy(current_config)
self._deep_merge(new_config, config_overrides)
# 验证新配置
self.validate_config(new_config)
# 推入配置栈
self.config_stack.append(new_config)
print(f"应用配置覆盖: {config_overrides}")
try:
yield new_config
finally:
# 弹出配置栈
self.config_stack.pop()
print("恢复原始配置")
@contextmanager
def environment_config(self, env_name: str):
"""环境配置上下文管理器"""
env_configs = {
'development': {
'database': {'host': 'localhost', 'port': 5432, 'database': 'dev_db'},
'logging': {'level': 'DEBUG'},
'debug': True
},
'testing': {
'database': {'host': 'localhost', 'port': 5433, 'database': 'test_db'},
'logging': {'level': 'WARNING'},
'debug': False
},
'production': {
'database': {'host': 'prod-db.example.com', 'port': 5432, 'database': 'prod_db'},
'logging': {'level': 'ERROR'},
'debug': False
}
}
if env_name not in env_configs:
raise ConfigurationError(f"未知的环境: {env_name}")
env_config = env_configs[env_name]
with self.config_context(**env_config):
print(f"切换到环境: {env_name}")
yield self.get_current_config()
def get_current_config(self) -> Dict[str, Any]:
"""获取当前配置"""
if self.config_stack:
return self.config_stack[-1]
return {}
def get_config_value(self, key: str, default: Any = None) -> Any:
"""获取配置值(支持点号分隔的嵌套键)"""
config = self.get_current_config()
keys = key.split('.')
current = config
for k in keys:
if isinstance(current, dict) and k in current:
current = current[k]
else:
return default
return current
# 配置管理系统演示
print("\n配置管理系统演示:")
# 创建配置文件
dev_config = {
"database": {
"host": "localhost",
"port": 5432,
"database": "myapp_dev",
"username": "dev_user",
"password": "dev_pass"
},
"logging": {
"level": "DEBUG",
"file": "app.log"
},
"cache": {
"enabled": True,
"ttl": 300
}
}
with open('dev_config.json', 'w') as f:
json.dump(dev_config, f, indent=2)
# 设置环境变量
os.environ['APP_DEBUG'] = 'true'
os.environ['APP_CACHE_TTL'] = '600'
config_manager = ConfigManager()
# 加载基础配置
base_config = config_manager.load_from_file('dev_config.json')
env_config = config_manager.load_from_env('APP_')
print(f"基础配置: {base_config}")
print(f"环境变量配置: {env_config}")
# 合并配置
merged_config = config_manager.merge_configs(base_config, env_config)
print(f"合并后配置: {merged_config}")
# 使用配置上下文
with config_manager.config_context(**merged_config) as config:
print(f"\n当前数据库主机: {config_manager.get_config_value('database.host')}")
print(f"当前日志级别: {config_manager.get_config_value('logging.level')}")
print(f"缓存TTL: {config_manager.get_config_value('cache.ttl')}")
# 临时覆盖配置
with config_manager.config_context(
database={'host': 'test-db.example.com', 'port': 5433},
logging={'level': 'WARNING'}
) as test_config:
print(f"\n测试环境数据库主机: {config_manager.get_config_value('database.host')}")
print(f"测试环境日志级别: {config_manager.get_config_value('logging.level')}")
print(f"测试环境数据库端口: {config_manager.get_config_value('database.port')}")
print(f"\n恢复后数据库主机: {config_manager.get_config_value('database.host')}")
# 环境配置切换
print("\n环境配置切换演示:")
for env in ['development', 'testing', 'production']:
with config_manager.environment_config(env) as env_config:
print(f"\n{env.upper()} 环境:")
print(f" 数据库: {config_manager.get_config_value('database.host')}:{config_manager.get_config_value('database.port')}")
print(f" 日志级别: {config_manager.get_config_value('logging.level')}")
print(f" 调试模式: {config_manager.get_config_value('debug')}")
# 清理测试文件
os.remove('dev_config.json')
os.environ.pop('APP_DEBUG', None)
os.environ.pop('APP_CACHE_TTL', None)
练习2:资源池管理系统
创建一个通用的资源池管理系统,支持不同类型的资源、连接限制、超时处理等功能。
# 练习2:资源池管理系统
print("\n=== 练习2:资源池管理系统 ===")
import threading
import queue
import time
from typing import TypeVar, Generic, Callable, Optional, Any
from contextlib import contextmanager
from dataclasses import dataclass
from enum import Enum
T = TypeVar('T')
class ResourceState(Enum):
"""资源状态"""
AVAILABLE = "available"
IN_USE = "in_use"
EXPIRED = "expired"
ERROR = "error"
@dataclass
class ResourceInfo:
"""资源信息"""
resource: Any
created_at: float
last_used: float
use_count: int
state: ResourceState
def is_expired(self, max_age: float) -> bool:
"""检查资源是否过期"""
return time.time() - self.created_at > max_age
def is_idle_too_long(self, max_idle: float) -> bool:
"""检查资源是否空闲过久"""
return time.time() - self.last_used > max_idle
class ResourcePoolError(Exception):
"""资源池异常"""
pass
class ResourcePool(Generic[T]):
"""通用资源池"""
def __init__(
self,
factory: Callable[[], T],
destroyer: Optional[Callable[[T], None]] = None,
max_size: int = 10,
min_size: int = 1,
max_age: float = 3600, # 1小时
max_idle: float = 300, # 5分钟
acquire_timeout: float = 30
):
self.factory = factory
self.destroyer = destroyer or (lambda x: None)
self.max_size = max_size
self.min_size = min_size
self.max_age = max_age
self.max_idle = max_idle
self.acquire_timeout = acquire_timeout
self._pool: queue.Queue[ResourceInfo] = queue.Queue(maxsize=max_size)
self._in_use: dict[T, ResourceInfo] = {}
self._lock = threading.RLock()
self._total_created = 0
self._total_destroyed = 0
# 预创建最小数量的资源
self._initialize_pool()
# 启动清理线程
self._cleanup_thread = threading.Thread(target=self._cleanup_worker, daemon=True)
self._cleanup_thread.start()
def _initialize_pool(self):
"""初始化资源池"""
for _ in range(self.min_size):
try:
resource = self._create_resource()
resource_info = ResourceInfo(
resource=resource,
created_at=time.time(),
last_used=time.time(),
use_count=0,
state=ResourceState.AVAILABLE
)
self._pool.put_nowait(resource_info)
except Exception as e:
print(f"初始化资源失败: {e}")
def _create_resource(self) -> T:
"""创建新资源"""
with self._lock:
if self._total_created >= self.max_size:
raise ResourcePoolError("资源池已达到最大容量")
resource = self.factory()
self._total_created += 1
print(f"创建新资源: {resource} (总计: {self._total_created})")
return resource
def _destroy_resource(self, resource_info: ResourceInfo):
"""销毁资源"""
try:
self.destroyer(resource_info.resource)
with self._lock:
self._total_destroyed += 1
print(f"销毁资源: {resource_info.resource} (总计: {self._total_destroyed})")
except Exception as e:
print(f"销毁资源失败: {e}")
def _cleanup_worker(self):
"""清理工作线程"""
while True:
try:
time.sleep(60) # 每分钟清理一次
self._cleanup_expired_resources()
except Exception as e:
print(f"清理线程异常: {e}")
def _cleanup_expired_resources(self):
"""清理过期资源"""
expired_resources = []
# 检查池中的资源
temp_resources = []
while not self._pool.empty():
try:
resource_info = self._pool.get_nowait()
if (resource_info.is_expired(self.max_age) or
resource_info.is_idle_too_long(self.max_idle)):
expired_resources.append(resource_info)
else:
temp_resources.append(resource_info)
except queue.Empty:
break
# 将未过期的资源放回池中
for resource_info in temp_resources:
try:
self._pool.put_nowait(resource_info)
except queue.Full:
expired_resources.append(resource_info)
# 销毁过期资源
for resource_info in expired_resources:
self._destroy_resource(resource_info)
if expired_resources:
print(f"清理了 {len(expired_resources)} 个过期资源")
@contextmanager
def acquire(self):
"""获取资源的上下文管理器"""
resource_info = None
start_time = time.time()
try:
# 尝试从池中获取资源
while resource_info is None:
try:
resource_info = self._pool.get(timeout=1.0)
break
except queue.Empty:
# 池为空,尝试创建新资源
try:
resource = self._create_resource()
resource_info = ResourceInfo(
resource=resource,
created_at=time.time(),
last_used=time.time(),
use_count=0,
state=ResourceState.AVAILABLE
)
except ResourcePoolError:
# 无法创建新资源,检查超时
if time.time() - start_time > self.acquire_timeout:
raise ResourcePoolError(f"获取资源超时 ({self.acquire_timeout}秒)")
continue
# 更新资源状态
resource_info.state = ResourceState.IN_USE
resource_info.last_used = time.time()
resource_info.use_count += 1
with self._lock:
self._in_use[resource_info.resource] = resource_info
print(f"获取资源: {resource_info.resource} (使用次数: {resource_info.use_count})")
yield resource_info.resource
except Exception as e:
if resource_info:
resource_info.state = ResourceState.ERROR
raise
finally:
if resource_info:
# 归还资源到池中
with self._lock:
self._in_use.pop(resource_info.resource, None)
if resource_info.state == ResourceState.ERROR:
# 错误状态的资源直接销毁
self._destroy_resource(resource_info)
else:
# 正常归还到池中
resource_info.state = ResourceState.AVAILABLE
resource_info.last_used = time.time()
try:
self._pool.put_nowait(resource_info)
print(f"归还资源: {resource_info.resource}")
except queue.Full:
# 池已满,销毁资源
self._destroy_resource(resource_info)
def get_stats(self) -> dict:
"""获取资源池统计信息"""
with self._lock:
return {
'pool_size': self._pool.qsize(),
'in_use': len(self._in_use),
'total_created': self._total_created,
'total_destroyed': self._total_destroyed,
'max_size': self.max_size,
'min_size': self.min_size
}
def close(self):
"""关闭资源池"""
print("关闭资源池...")
# 销毁池中的所有资源
while not self._pool.empty():
try:
resource_info = self._pool.get_nowait()
self._destroy_resource(resource_info)
except queue.Empty:
break
# 销毁正在使用的资源
with self._lock:
for resource_info in list(self._in_use.values()):
self._destroy_resource(resource_info)
self._in_use.clear()
# 数据库连接模拟
class MockDatabaseConnection:
"""模拟数据库连接"""
_connection_counter = 0
def __init__(self):
MockDatabaseConnection._connection_counter += 1
self.id = MockDatabaseConnection._connection_counter
self.connected = True
print(f" -> 建立数据库连接 {self.id}")
def execute(self, sql: str):
"""执行SQL"""
if not self.connected:
raise RuntimeError("连接已关闭")
print(f" -> 连接 {self.id} 执行: {sql}")
return f"Result from connection {self.id}"
def close(self):
"""关闭连接"""
if self.connected:
self.connected = False
print(f" -> 关闭数据库连接 {self.id}")
def __str__(self):
return f"DBConn_{self.id}"
# 资源池演示
print("\n资源池管理系统演示:")
# 创建数据库连接池
db_pool = ResourcePool(
factory=MockDatabaseConnection,
destroyer=lambda conn: conn.close(),
max_size=5,
min_size=2,
max_age=10, # 10秒过期(演示用)
max_idle=5, # 5秒空闲过期
acquire_timeout=5
)
print(f"\n初始状态: {db_pool.get_stats()}")
# 单个资源使用
print("\n1. 单个资源使用:")
with db_pool.acquire() as conn:
result = conn.execute("SELECT * FROM users")
print(f"查询结果: {result}")
print(f"使用后状态: {db_pool.get_stats()}")
# 并发资源使用
print("\n2. 并发资源使用:")
def worker(worker_id, num_operations):
"""工作线程"""
for i in range(num_operations):
try:
with db_pool.acquire() as conn:
conn.execute(f"Worker {worker_id} - Operation {i+1}")
time.sleep(0.1) # 模拟操作耗时
except Exception as e:
print(f"Worker {worker_id} 错误: {e}")
# 启动多个工作线程
threads = []
for i in range(3):
thread = threading.Thread(target=worker, args=(i+1, 2))
threads.append(thread)
thread.start()
# 等待所有线程完成
for thread in threads:
thread.join()
print(f"\n并发使用后状态: {db_pool.get_stats()}")
# 测试资源池限制
print("\n3. 测试资源池限制:")
connections = []
try:
# 尝试获取超过最大数量的连接
for i in range(7): # 超过max_size=5
conn_context = db_pool.acquire()
conn = conn_context.__enter__()
connections.append((conn_context, conn))
print(f"获取连接 {i+1}: {conn}")
except ResourcePoolError as e:
print(f"资源池限制: {e}")
finally:
# 释放所有连接
for conn_context, conn in connections:
try:
conn_context.__exit__(None, None, None)
except:
pass
print(f"\n释放后状态: {db_pool.get_stats()}")
# 等待一段时间让清理线程工作
print("\n4. 等待资源清理...")
time.sleep(6) # 等待资源过期
print(f"清理后状态: {db_pool.get_stats()}")
# 关闭资源池
db_pool.close()
print(f"\n关闭后状态: {db_pool.get_stats()}")
总结
核心知识点
-
上下文管理器协议
__enter__和__exit__方法- 异常处理和资源清理
- 返回值和异常抑制
-
contextlib模块
@contextmanager装饰器ExitStack动态管理suppress异常抑制- 输出重定向工具
-
高级模式
- 装饰器形式的上下文管理器
- 上下文管理器链和组合
- 条件和缓存上下文管理器
- 异步上下文管理器
-
实际应用
- 资源管理(文件、数据库、网络)
- 状态管理(配置、环境、属性)
- 性能监控和调试
- 事务和锁管理
技能掌握
🟢 基础级别
- 理解上下文管理器的概念和作用
- 使用
with语句进行文件操作 - 实现简单的自定义上下文管理器
- 使用
@contextmanager装饰器
🟡 中级级别
- 掌握异常处理和资源清理机制
- 使用
contextlib模块的各种工具 - 实现复杂的资源管理上下文管理器
- 理解上下文管理器的执行流程
🔴 高级级别
- 设计可重用的上下文管理器模式
- 实现异步上下文管理器
- 创建上下文管理器链和组合
- 优化上下文管理器的性能
最佳实践
设计原则
- 确保资源的正确获取和释放
- 提供清晰的错误处理机制
- 支持嵌套和组合使用
- 保持接口的简洁性
性能考虑
- 避免在
__enter__和__exit__中执行耗时操作 - 合理使用资源池和缓存
- 考虑并发安全性
- 优化异常处理路径
错误处理
- 在
__exit__中正确处理异常 - 提供有意义的错误信息
- 确保资源清理的可靠性
- 考虑异常传播和抑制
可维护性
- 使用描述性的类名和方法名
- 提供完整的文档和示例
- 支持配置和定制
- 遵循单一职责原则
常见陷阱
资源管理
- 忘记在
__exit__中释放资源 - 异常情况下的资源泄漏
- 重复释放资源导致错误
- 不正确的异常处理
并发问题
- 线程安全性考虑不足
- 死锁和竞态条件
- 资源竞争和饥饿
- 异步上下文的同步问题
性能问题
- 过度创建和销毁资源
- 不必要的同步开销
- 内存泄漏和引用循环
- 异常处理的性能影响
设计问题
- 上下文管理器职责过重
- 缺乏适当的抽象层次
- 硬编码的配置和限制
- 不支持嵌套和组合
性能考虑
资源开销
- 上下文管理器的创建和销毁成本
- 资源获取和释放的时间
- 内存使用和垃圾回收影响
- 异常处理的性能开销
优化策略
- 使用资源池减少创建销毁开销
- 实现资源的延迟初始化
- 优化异常处理路径
- 考虑使用
__slots__减少内存使用
监控和调试
- 添加性能监控和统计
- 提供调试和诊断工具
- 记录资源使用情况
- 分析瓶颈和优化点
下一步学习
- 闭包与作用域 - 理解Python的作用域规则和闭包机制
- lambda表达式与函数式编程 - 掌握函数式编程范式
- 异步编程与协程 - 深入学习异步上下文管理器
- 多线程与并发编程 - 理解并发环境下的上下文管理
扩展阅读
更新时间: 2024-12-19
版本: v1.0.0
作者: Python教程团队


1468

被折叠的 条评论
为什么被折叠?



