为了在
await
表示
__await__
不需要是发电机。但是,某些操作仅在以下情况下可用:
__等待__
支持发电机接口。
也就是说,不可能
send
值或
throw
迭代器中的异常-
__等待__
。只有
None
可以“发送”到迭代器-
__等待__
,好像
generator.__next__
已使用。
让我们考虑一个简单的
Awaitable
从其
__等待__
。
class Iter:
"""Basic iterator that yields the same value"""
def __next__(self): return 1
def __iter__(self): return self
class IterAwait:
"""Awaitable that uses an iterator for __await__"""
def __await__(self):
return Iter()
我们可以检查它们是否实现了所需的接口:
>>> from collections.abc import Awaitable, Iterator, Generator
>>> isinstance(IterAwait(), Awaitable)
True
>>> isinstance(IterAwait().__await__(), Iterator)
True
>>> isinstance(IterAwait().__await__(), Generator)
False
为了了解这与
等候
,我们将其包装在一个协同程序中:
async def iter_await():
await IterAwait()
我们执行的每个操作
iter_await
通过以下方式转发完整的协同程序/生成器接口
等候
到我们的迭代器-
__等待__
。这允许研究迭代器如何-
__等待__
接收信号:
>>> test_iter = iter_await()
>>> test_iter.send(3) # 0. does it appear like a coroutine?
TypeError: can`t send non-None value to a just-started coroutine
>>> test_iter.send(None) # 1. must initialise just-started coroutine
1
>>> test_iter.send(None) # 2. repeatedly use the underlying iterator
1
>>> next(test_iter) # 3. do we expose the iterator?
TypeError: 'coroutine' object is not an iterator
>>> test_iter.send(3) # 4. can we send non-None values?
AttributeError: 'Iter' object has no attribute 'send'
>>> test_iter = iter_await() # we just broke the coroutine...
>>> test_iter.send(None) # ...need a new one
1
>>> test_iter.throw(KeyError) # 4. can we throw Exceptions?
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in iter_await
KeyError
可以看出,
等候
可以处理迭代器-
__等待__
,但不转发所有操作。然而,有些是翻译的,有些是提前处理的。
-
始终可以
.send(None)
,转换为裸体
__next__()
。(1、2)
-
协同程序不会神奇地暴露
.__next__
(3) 无法翻译
.send
值为(4)。
-
有可能
.throw
例外,但
等候
在协同程序的早期处理它。
请注意
等候
使用
投
和
邮寄
方法可用。如果结果
__等待__
机具
邮寄
但不是
投
反之亦然,则使用当前的功能。只有
__next__
是强制性的。