普通同步contextmanager中是否可以使用await异步调用?
能否在上下文管理器中使用await调用
普通同步上下文管理器不支持直接使用await,你遇到的"await" allowed only within async function报错是Python语法的正常约束:
- 用
contextlib.contextmanager装饰器定义的是同步上下文管理器,本质是同步生成器函数,运行在同步执行上下文里 - 同步上下文管理器配套使用的
with关键字块本身也是同步上下文,不允许直接书写await表达式
你给出的测试代码就是典型的错误写法:
from contextlib import contextmanager @contextmanager def sample_contextmanager(): # 仅支持同步调用 yield # 仅支持同步调用 # 错误:同步with块内不允许直接使用await with sample_contextmanager(): await some_coroutine()
如果需要在上下文管理器的进入/退出逻辑、以及上下文包裹的代码块中使用await,请使用Python标准库提供的异步上下文管理器实现:
- 从
contextlib导入asynccontextmanager装饰器,替代同步版本的contextmanager - 定义上下文管理器的函数必须加
async关键字声明为异步函数 - 调用上下文管理器时必须使用
async with关键字,而非同步的with
正确示例代码如下:
from contextlib import asynccontextmanager @asynccontextmanager async def sample_async_contextmanager(): # 进入上下文阶段可以正常写await异步调用 await async_setup_step() yield # 退出上下文阶段也可以正常写await异步调用 await async_teardown_step() async def run_task(): # 必须用async with调用异步上下文管理器 async with sample_async_contextmanager(): # 块内可以正常执行await异步调用 await some_coroutine()
注意:同步和异步上下文管理器的装饰器、调用关键字不能混用,否则会触发语法错误或者运行时异常。
内容的提问来源于stack exchange,提问作者Apollos Kim
相关产品推荐
相关产品推荐

