__等待_需要成为发电机吗?

2022-04-18 00:00:00 python python-asyncio python-3.5

问题描述

我要实现一个可等待的,并注意到__await__‘需要’成为一个生成器。

发件人PEP-492:

具有返回迭代器的__await__方法的对象。

...

在本PEP的其余部分中,使用__await__方法的对象称为类Future对象。

如果__await__返回的不是迭代器,则为TypeError。

根据我的经验,在await成为语句之前,yield from与作为生成器实现的协程一起使用。如今,Python(我使用的是3.5)拥有使用async def语法的异步方法。因此,我认为yield from语法是旧的/不推荐使用的。

所以我打开了解释器,看看这是如何工作的:

>>> class A:
...     def __await__(self):
...         yield from (asyncio.sleep(1).__await__())
...         return 'spam'
... 
>>> a = A()
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.5/asyncio/base_events.py", line 467, in run_until_complete
    return future.result()
  File "/usr/lib64/python3.5/asyncio/futures.py", line 294, in result
    raise self._exception
  File "/usr/lib64/python3.5/asyncio/tasks.py", line 240, in _step
    result = coro.send(None)
  File "/usr/lib64/python3.5/asyncio/tasks.py", line 585, in _wrap_awaitable
    return (yield from awaitable.__await__())
  File "<stdin>", line 3, in __await__
AttributeError: 'generator' object has no attribute '__await__'

因此,asyncio.sleep似乎没有__await__方法。使用这种yield from语法也感觉很别扭。

所以我决定尝试async语法,看看它是否有效:

>>> class A:
...     async def __await__(self):
...         await asyncio.sleep(1)
...         return 'spam'
... 
>>> a = A()
>>> 
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(a)
'spam'

它似乎真的起作用了!所以现在我想知道,__await__方法是否真的需要成为使用yield from语法的生成器?


编辑:当添加一个间接级别时,因此在await语句中使用可等待值时,问题变得很明显:

>>> async def test():
...     return await A()
... 
>>> loop.run_until_complete(test())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
    return future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 274, in result
    raise self._exception
  File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
    result = coro.send(None)
  File "<stdin>", line 2, in test
TypeError: __await__() returned a coroutine

因此它实际上需要返回一个生成器,如下所示:

class A:
    def __await__(self):
        yield from asyncio.sleep(1)
        return 'spam'    

解决方案

因此看起来asyncio.sleep没有__await__方法

没错,但它不一定要有一个才能等待。documentation表示,如果存在__await__,则需要返回迭代器,而不是await将只对定义__await__的对象起作用。事实上,它显式地记录了await的参数可以是:

之一
  • A从本机协程函数返回的本机协程对象。

  • types.coroutine()修饰的函数返回的基于生成器的协程对象。

  • 具有返回迭代器的__await__方法的对象。

    /li>
  • 用C定义的对象,提供与__await__特殊方法等效的Python/C。

所以现在我想知道,__await__方法真的需要成为使用Year From语法的生成器吗?

如果您实际有__await__方法,则它确实需要返回迭代器。

相关文章