__await__ 的精确规范

Python语言参考指定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())

RuntimeError: Task got bad yield: 0

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


编辑:据我所知,这在任何地方都没有记录。asyncio但我一直在自己调查,我认为理解期望其协程产生什么对象的关键task_step_impl在于_asynciomodule.c.


更新:我已经向 cpython 存储库发出了 PR,目的是澄清这一点: “澄清”的模糊规范object.__await__

PR 现已合并,并且应该可以在 Python 3.10+ 的文档中找到。


ABOUTYOU
浏览 1599回答 2
2回答

温温酱

该语言并不关心您返回哪个迭代器。该错误来自asyncio库,该库对迭代器必须生成的值类型有特定的想法。Asyncio 需要__await__生成 asyncio future(包括其子类型,例如任务)或None. 其他库,如 curio 和 trio,将期望不同类型的值。总的来说,异步库不会记录他们的期望,__await__因为他们认为这是一个实现细节。就 asyncio 而言,除了协程之外,您还应该使用更高级别的构造,例如 future 和任务,并等待它们。很少需要__await__手动实现,即使这样,您也应该使用它来委托另一个可等待的信号。编写一个__await__创建并产生自己的新挂起值的方法需要将其与事件循环结合起来并了解其内部结构。您可以将其视为__await__编写类似于 asyncio 的库的工具。如果您是此类库的作者,则当前规范就足够了,因为您可以从迭代器中生成任何您喜欢的内容,只有事件循环中的代码才会观察生成的值。如果您不处于这个位置,您可能不需要实施__await__.

一只萌萌小番薯

任务只能等待其他任务/未来。来自CPython 源代码:   /* Check if `result` is FutureObj or TaskObj (and not a subclass) */    /* ... */    /* Check if `result` is None */    /* ... error */    /* Check if `result` is a Future-compatible object */    /* ... */    /* Check if `result` is a generator */    /* ... */    /* The `result` is none of the above */    o = task_set_error_soon(        task, PyExc_RuntimeError, "Task got bad yield: %R", result);    Py_DECREF(result);    return o;编辑:如果我理解正确的话,此限制仅施加于任务,并且正常的 future 可以等待从 返回的任何可迭代对象__await__,尽管重点可能是返回的可迭代对象产生事件循环,然后最终返回结果。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python