__等待_需要成为发电机吗?
问题描述
我要实现一个可等待的,并注意到__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()
修饰的函数返回的基于生成器的协程对象。具有返回迭代器的
/li>__await__
方法的对象。用C定义的对象,提供与
__await__
特殊方法等效的Python/C。
所以现在我想知道,
__await__
方法真的需要成为使用Year From语法的生成器吗?
如果您实际有__await__
方法,则它确实需要返回迭代器。
相关文章