contextlib
上下文管理器保证进入和退出成对执行,适合文件、锁、数据库连接和临时配置。with 块即使发生异常也会执行清理。
closing 与 suppress
from contextlib import closing, suppress
from urllib.request import urlopen
with closing(urlopen("https://example.com")) as response:
print(response.status)
with suppress(FileNotFoundError):
__import__("pathlib").Path("cache.tmp").unlink()
closing 会在退出时调用对象的 close();suppress 只适合明确、可忽略的异常,不能包住大段业务代码,否则会掩盖错误。
@contextmanager
from contextlib import contextmanager
@contextmanager
def temporary(value):
print("开始", value)
try:
yield value
finally:
print("清理")
with temporary("任务") as item:
print(item)
yield 前是进入逻辑,yield 后或 finally 是退出逻辑。清理代码必须放在 finally;若需要处理异常,可在 yield 周围捕获后重新抛出。
ExitStack:动态管理多个资源
from contextlib import ExitStack
with ExitStack() as stack:
files = [stack.enter_context(open(name, encoding="utf-8")) for name in ["a.txt", "b.txt"]]
text = "".join(file.read() for file in files)
资源会按后进先出顺序关闭。stack.callback(func, *args) 可注册任意清理函数,适合资源数量运行时才确定的场景。
异步上下文
@asynccontextmanager 和 AsyncExitStack 用于 async with。不要在同步上下文中阻塞异步资源,也不要忘记 await 清理操作。上下文管理器负责资源生命周期,不应悄悄吞掉未知异常。