0Pricing
Python Academy · 课时

contextlib:@contextmanager

使用 contextlib 装饰器简洁地创建上下文管理器。

contextlib:@contextmanager 是 CoddyKit 上的免费 Python Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Python Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Python Academy 课程共包含 4 节课。

为什么使用 contextlib?

contextlib.contextmanager 允许您将上下文管理器写成生成器函数,而不是类,从而减少样板代码。

from contextlib import contextmanager

@contextmanager
def managed():
    print("setup")
    yield
    print("teardown")

with managed():
    print("inside")

生成值

您 yield 的任何值,都会绑定到 with 语句中的 as 变量。

from contextlib import contextmanager

@contextmanager
def temp_list():
    lst = []
    yield lst
    print(f"Final list: {lst}")

with temp_list() as lst:
    lst.append(1)
    lst.append(2)

@contextmanager 中的异常处理

请将 yield 放在 try/finally 中,以确保即使发生异常也能完成清理。

from contextlib import contextmanager

@contextmanager
def safe_open(path):
    f = open(path)
    try:
        yield f
    finally:
        f.close()

with safe_open("data.txt") as f:
    print(f.read())

抑制异常

在生成器内部捕获异常即可抑制它——这与从 __exit__ 返回 True 相同。

from contextlib import contextmanager

@contextmanager
def ignore_value_errors():
    try:
        yield
    except ValueError:
        pass

with ignore_value_errors():
    raise ValueError("ignored")

contextlib.suppress

contextlib.suppress(*exceptions) 是一个现成的上下文管理器,可抑制指定的异常类型。

from contextlib import suppress

with suppress(FileNotFoundError):
    open("missing.txt")

print("continues")

contextlib.closing

closing(obj) 会创建一个上下文管理器,在退出时调用 obj.close()。它适用于具有 close() 但没有 __exit__ 的对象。

from contextlib import closing
from urllib.request import urlopen

with closing(urlopen("https://example.com")) as page:
    content = page.read()

contextlib.nullcontext

nullcontext 是一个不执行任何操作的上下文管理器。当上下文管理器是可选项时很有用。

from contextlib import nullcontext

def process(data, lock=None):
    cm = lock if lock is not None else nullcontext()
    with cm:
        return [x*2 for x in data]

contextlib.ExitStack

ExitStack 允许您动态管理数量可变的上下文管理器。

from contextlib import ExitStack

files = ["a.txt", "b.txt", "c.txt"]
with ExitStack() as stack:
    handles = [stack.enter_context(open(f)) for f in files]
    data = [h.read() for h in handles]

重复使用 @contextmanager

基于生成器的上下文管理器每次调用只能使用一次。要重复使用它,请再次调用经过装饰的函数。

from contextlib import contextmanager

@contextmanager
def counter():
    count = 0
    yield lambda: count.__add__  # each call is independent
    print("done")

with counter():
    pass
with counter():
    pass

asynccontextmanager

对于异步代码,请使用 contextlib.asynccontextmanager,将 async with 管理器写成生成器。

from contextlib import asynccontextmanager

@asynccontextmanager
async def async_session():
    session = await create_session()
    try:
        yield session
    finally:
        await session.close()

contextlib.redirect_stdout

将标准输出临时重定向到任意类似文件的对象。

import io
from contextlib import redirect_stdout

buf = io.StringIO()
with redirect_stdout(buf):
    print("captured")

print(buf.getvalue())  # captured

快速检查

在 @contextmanager 生成器中,应将清理代码放在哪里,才能确保即使发生异常也会执行?

总结

@contextmanager 会将生成器转换为上下文管理器。请在 yield 周围使用 try/finally 来安全地完成清理。contextlib 模块还提供 suppress、nullcontext、ExitStack 等工具。

常见问题解答

「contextlib:@contextmanager」课时是免费的吗?

是的 — 「contextlib:@contextmanager」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Python Academy 课程的其余内容,请升级到 CoddyKit PRO。 Python Academy 课程共包含 4 节课。

「contextlib:@contextmanager」这节课中我会学到什么?

使用 contextlib 装饰器简洁地创建上下文管理器。 你通过在浏览器中直接运行的动手代码来练习 Python Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Python Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Python Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「contextlib:@contextmanager」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Python Academy 课中编写并运行代码吗?

能。每节 Python Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 深入理解 with 语句
  2. __enter__ 与 __exit__ 协议
  3. contextlib:@contextmanager
  4. 实用的上下文管理器模式
← 返回 Python Academy