async def 函数中不能用 yield from 委托异步生成器,会报 SyntaxError;正确方式是 async for 遍历再 yield,以兼容 aiter__/__anext 协议并支持取消。

yield from 在 async def 函数里直接报错
async def 定义的是协程函数或异步生成器,但 yield from 本身不支持 await 行为,所以不能直接在 async def 函数中使用 yield from 委托另一个异步生成器。Python 会抛出 SyntaxError: 'yield from' inside async function。
这是因为 yield from 是同步委托协议(基于 __iter__ 和 send()),而异步生成器走的是 __aiter__ / __anext__ 协议,二者不兼容。
- 想委托另一个异步生成器,必须用
async for+yield - 如果被委托对象是普通同步生成器,
yield from可以用,但整个函数不能是async def(否则类型混用会出逻辑问题) - 混合使用同步/异步生成器需格外小心——比如在
async def中yield from同步生成器,虽然语法允许,但会阻塞事件循环
异步生成器中委托另一个异步生成器的正确写法
必须显式迭代并逐个 yield,即用 async for 遍历目标异步生成器,再用 yield 转发值。这是唯一符合语义且不破坏异步流的方式。
async def inner():
yield 1
yield 2
async def outer():
async for x in inner(): # ✅ 正确:用 async for 拉取
yield x # ✅ 再 yield 出去
- 不能写成
yield from inner()—— 语法错误 - 不能写成
yield await inner()——inner()返回的是异步生成器对象,不是可 await 的协程 - 如果需要提前终止委托(如收到 cancel),
async for会自动调用aclose(),这点比手动管理更安全
yield from 在普通生成器中能用,但和异步场景语义完全不同
在 def 定义的同步生成器里,yield from 是语法糖,等价于手动 for + yield,并自动处理 StopIteration、throw()、close() 等委托逻辑。
def sync_inner():
yield 'a'
yield 'b'
def sync_outer():
yield from sync_inner() # ✅ 合法,且会透传 close()/throw()
- 它背后调用的是被委托对象的
__iter__和send(),全程同步阻塞 - 若误把异步生成器传给
yield from(如yield from async_gen()),运行时会报TypeError: 'async_generator' object is not iterable - 即便包装成
awaitable,也无法绕过协议不匹配的根本限制
性能与控制流差异:为什么不能“自动适配”
异步生成器的每次 yield 都对应一次 await __anext__() 调用,涉及事件循环调度;而 yield from 的委托是纯用户态栈操作,无调度开销。两者调度粒度和错误传播路径完全不同。
-
async for+yield多一层协程帧,但保证了 await 点清晰、取消信号可捕获 - 试图用
loop.run_in_executor包装同步yield from来“桥接”,会导致事件循环被阻塞,完全违背异步初衷 - CPython 目前没有提供类似
yield from awaitable的语法糖,也不太可能加——协议层级差异太大
真正容易被忽略的是异常传播:在 async for 块中,GeneratorExit 会变成 AsyncGeneratorExit,且 throw() 不再可用,只能靠 aclose() 或取消任务来中断。










