关于 python-resource-management
面向 Python 开发者,介绍数据库连接、文件和套接字等资源的确定性清理。内容涵盖同步与异步上下文管理器、异常行为及可复用的清理模式。
主要功能
- 01使用同步上下文管理器
- 02实现异步上下文管理器
- 03确保异常后仍释放资源
- 04处理嵌套资源清理
- 05用 contextlib 装饰器创建管理器
适用场景
- 01管理数据库连接和连接池
- 02确保文件句柄在错误后关闭
- 03构建带状态的流式响应
- 04动态清理多个资源
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ wshobson/ agents --skill python-resource-management安装后在 Claude Code 中输入/python-resource-management确认已加载。
附带文件references/details.md
详细介绍
Python 资源管理
使用上下文管理器确定性地管理资源。数据库连接、文件句柄和网络套接字等资源应可靠释放,即使发生异常也不例外。
何时使用本技能
- 管理数据库连接和连接池
- 处理文件句柄和 I/O
- 实现自定义上下文管理器
- 构建带状态的流式响应
- 处理嵌套资源清理
- 创建异步上下文管理器
核心概念
1. 上下文管理器
with 语句确保资源自动释放,即使发生异常也不例外。
2. 协议方法
__enter__/__exit__ 用于同步,__aenter__/__aexit__ 用于异步资源管理。
3. 无条件清理
无论是否发生异常,__exit__ 始终执行。
4. 异常处理
从 __exit__ 返回 True 可抑制异常,返回 False 则传播异常。
快速开始
from contextlib import contextmanager
@contextmanager
def managed_resource():
resource = acquire_resource()
try:
yield resource
finally:
resource.cleanup()
with managed_resource() as r:
r.do_work()
基本模式
模式 1:基于类的上下文管理器
为复杂资源实现上下文管理器协议。
class DatabaseConnection:
"""Database connection with automatic cleanup."""
def __init__(self, dsn: str) -> None:
self._dsn = dsn
self._conn: Connection | None = None
def connect(self) -> None:
"""Establish database connection."""
self._conn = psycopg.connect(self._dsn)
def close(self) -> None:
"""Close connection if open."""
if self._conn is not None:
self._conn.close()
self._conn = None
def __enter__(self) -> "DatabaseConnection":
"""Enter context: connect and return self."""
self.connect()
return self
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None:
"""Exit context: always close connection."""
self.close()
# Usage with context manager (preferred)
with DatabaseConnection(dsn) as db:
result = db.execute(query)
# Manual management when needed
db = DatabaseConnection(dsn)
db.connect()
try:
result = db.execute(query)
finally:
db.close()
模式 2:异步上下文管理器
对于异步资源,实现异步协议。
class AsyncDatabasePool:
"""Async database connection pool."""
def __init__(self, dsn: str, min_size: int = 1, max_size: int = 10) -> None:
self._dsn = dsn
self._min_size = min_size
self._max_size = max_size
self._pool: asyncpg.Pool | None = None
async def __aenter__(self) -> "AsyncDatabasePool":
"""Create connection pool."""
self._pool = await asyncpg.create_pool(
self._dsn,
min_size=self._min_size,
max_size=self._max_size,
)
return self
async def __aexit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None:
"""Close all connections in pool."""
if self._pool is not None:
await self._pool.close()
async def execute(self, query: str, *args) -> list[dict]:
"""Execute query using pooled connection."""
async with self._pool.acquire() as conn:
return await conn.fetch(query, *args)
# Usage
async with AsyncDatabasePool(dsn) as pool:
users = await pool.execute("SELECT * FROM users WHERE active = $1", True)
模式 3:使用 @contextmanager 装饰器
对于简单直接的情况,使用该装饰器简化上下文管理器。
from contextlib import contextmanager, asynccontextmanager
import time
import structlog
logger = structlog.get_logger()
@contextmanager
def timed_block(name: str):
"""Time a block of code."""
start = time.perf_counter()
try:
yield
finally:
elapsed = time.perf_counter() - start
logger.info(f"{name} completed", duration_seconds=round(elapsed, 3))
# Usage
with timed_block("data_processing"):
process_large_dataset()
@asynccontextmanager
async def database_transaction(conn: AsyncConnection):
"""Manage database transaction."""
await conn.execute("BEGIN")
try:
yield conn
await conn.execute("COMMIT")
except Exception:
await conn.execute("ROLLBACK")
raise
# Usage
async with database_transaction(conn) as tx:
await tx.execute("INSERT INTO users ...")
await tx.execute("INSERT INTO audit_log ...")
模式 4:无条件释放资源
无论是否发生异常,始终在 __exit__ 中清理资源。
class FileProcessor:
"""Process file with guaranteed cleanup."""
def __init__(self, path: str) -> None:
self._path = path
self._file: IO | None = None
self._temp_files: list[Path] = []
def __enter__(self) -> "FileProcessor":
self._file = open(self._path, "r")
return self
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None:
"""Clean up all resources unconditionally."""
# Close main file
if self._file is not None:
self._file.close()
# Clean up any temporary files
for temp_file in self._temp_files:
try:
temp_file.unlink()
except OSError:
pass # Best effort cleanup
# Return None/False to propagate any exception
详细示例与模式
详细章节(以 ## Advanced Patterns 开头)位于 references/details.md。当上述导航摘要不够用时,请阅读该文件。
最佳实践总结
- 始终使用上下文管理器 - 适用于任何需要清理的资源
- 无条件清理 -
__exit__即使发生异常也会执行 - 不要意外抑制异常 - 除非有意抑制,否则返回
False - 使用 @contextmanager - 适用于简单的资源模式
- 实现两种协议 - 同时支持
with和手动管理 - 使用 ExitStack - 适用于资源数量动态变化的情况
- 高效累积 - 使用列表 + join,而非字符串拼接
- 跟踪指标 - 首字节时间对流式处理至关重要
- 记录行为 - 尤其是异常抑制
- 测试清理路径 - 验证出错时资源能够释放
评论
支持 Markdown