为什么我不能在异步函数中使用'yield from'?

46
在Python 3.6中,我可以在协程中使用yield,但是我无法使用yield from。以下是我的代码。第3行我等待另一个协程。第4行我尝试yield from一个文件。为什么Python 3.6不允许我这样做呢?
async def read_file(self, filename):
    with tempfile.NamedTemporaryFile(mode='r', delete=True, dir='/tmp', prefix='sftp') as tmp_file:
        await self.copy_file(filename, tmp_file)
        yield from open(tmp_file)

这是Python 3.6针对上述代码引发的异常:

  File "example.py", line 4
    yield from open(tmp_file)
    ^
SyntaxError: 'yield from' inside async function

@asyncio.coroutine 装饰器是否真的可以用于启用异步函数中的 "yield from"?根据 asyncio 文档: "@asyncio.coroutine¶ 用于标记基于生成器的协程的装饰器。这使得生成器使用 yield from 来调用 async def 协程,并且还使得生成器可以被 async def 协程调用,例如使用 await 表达式。" 我不确定这是否适用于您上面编写的代码... - Jasha
请参阅 https://dev59.com/o1kS5IYBdhLWcg3wl32I。 - Jasha
1个回答

59
根据 PEP 525,Python 3.6 引入了异步生成器:

Asynchronous yield from

While it is theoretically possible to implement yield from support for asynchronous generators, it would require a serious redesign of the generators implementation.

yield from is also less critical for asynchronous generators, since there is no need provide a mechanism of implementing another coroutines protocol on top of coroutines. And to compose asynchronous generators a simple async for loop can be used:

async def g1():
    yield 1
    yield 2

async def g2():
    async for v in g1():
        yield v
正如你所看到的,答案归结为“实现起来太困难,而且你也不需要它”。

11
尽管使用 yield from 会让代码显得混乱,但它确实可以让你透明地委派生成器并充分利用 yield 表达式(即同时接收值和生成值)。如果没有 yield from,那么在将生成的值传递给调用者、将接收到的值传递给子生成器以及处理所有特殊异常时,代码将变得非常混乱。 - Anakhand

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接