__await__ 的精确规范

Ana*_*and 9 python async-await python-asyncio

Python Language Reference 规定object.__await__如下:

object.__await__(self)

必须返回一个迭代器。应该用于实现可等待的对象。例如,asyncio.Future实现此方法以与 await 表达式兼容。

就是这样。我觉得这个规范很模糊,也不是很具体(讽刺的是)。好的,它应该返回一个迭代器,但它可以是一个任意的迭代器吗?显然不是:

import asyncio


class Spam:
    def __await__(self):
        yield from range(10)


async def main():
    await Spam()


asyncio.run(main())
Run Code Online (Sandbox Code Playgroud)
RuntimeError: Task got bad yield: 0
Run Code Online (Sandbox Code Playgroud)

我假设asyncio事件循环期望迭代器产生特定类型的对象。那么它究竟应该产生什么?(为什么没有记录在案?)


编辑:据我所知,这在任何地方都没有记录。但我一直在调查我自己,我觉得关键是了解哪些对象asyncio预计其协同程序产生在于task_step_impl_asynciomodule.c


更新:我做了一个PR与此澄清的目的CPython的库:“明确的模糊规范object.__await__。目前正在审核中。

use*_*342 9

语言不关心您返回哪个迭代器。该错误来自asyncio,它对迭代器必须生成的值类型有特定的想法。Asyncio 需要__await__生成 asyncio 期货(包括它们的子类型,例如任务)或None. 其他库,如 curio 和 trio,将期待不同类型的值。异步库基本上没有记录他们的期望,__await__因为他们认为这是一个实现细节。

就 asyncio 而言,除了协程之外,您还应该使用更高级别的构造,例如期货和任务,并等待它们。很少需要__await__手动实现,即便如此,您也应该使用它来委托另一个可等待的信号。编写一个__await__创建并产生它自己的新挂起值的 ,需要它与事件循环耦合并了解其内部结构。

您可以将其__await__视为编写类似于 asyncio 的库的工具。如果你是这样一个库的作者,当前的规范就足够了,因为你可以从迭代器中产生任何你喜欢的东西,只有你的事件循环中的代码会观察产生的值。如果您不在那个位置,您可能不需要实施__await__.

  • 这样就清楚了。尽管编写该规范的人至少应该关心添加一些内容,例如“此迭代器期望的值特定于事件循环实现”,特别是关于“asyncio”的注释(即“仅从“asyncio”产生) `任务、未来和协程”)。 (2认同)