为了账号安全,请及时绑定邮箱和手机立即绑定

__await__ 的精确规范

__await__ 的精确规范

ABOUTYOU 2023-08-22 15:01:45
Python语言参考指定object.__await__如下:object.__await__(self)必须返回一个迭代器。应该用于实现可等待的对象。例如,asyncio.Future实现此方法以与await 表达式兼容。就是这样。我发现这个规范非常模糊而且不是很具体(讽刺的是)。好的,它应该返回一个迭代器,但是它可以是任意迭代器吗?很明显不是:import asyncioclass 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+ 的文档中找到。
查看完整描述

2 回答

?
温温酱

TA贡献1752条经验 获得超4个赞

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

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

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


查看完整回答
反对 回复 2023-08-22
?
一只萌萌小番薯

TA贡献1795条经验 获得超7个赞

任务只能等待其他任务/未来。来自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__,尽管重点可能是返回的可迭代对象产生事件循环,然后最终返回结果。



查看完整回答
反对 回复 2023-08-22
  • 2 回答
  • 0 关注
  • 1599 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信