考虑这个简单的协程
In [9]: async def coro():
...: print('hello world')
...:
我们知道原生协同程序不是迭代器
In [12]: type(c)
Out[12]: coroutine
In [13]: next(c)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-13-e846efec376d> in <module>()
----> 1 next(c)
TypeError: 'coroutine' object is not an iterator
但是,如果我运行协程,我会收到StopIteration
错误。
In [10]: c = coro()
In [11]: c.send(None)
hello world
---------------------------
StopIteration Traceback (most recent call last)
<ipython-input-11-d9162d5dda48> in <module>()
----> 1 c.send(None)
StopIteration:
this回答本地协同例程在功能上等同于基于协同生成的协同程序。但同一问题的另一个答案更进一步,并解释了它们如何为不同的目的服务。
本机coros引发StopIteration
错误的唯一原因是它们与基于生成器的coros共享重要代码?或者还有其他一些原因?
答案 0 :(得分:1)
我认为没有人在PEP 492背后的讨论中明确地将此作为明确的设计选择进行讨论,但我认为它们不是只是它们碰巧共享重要的代码,而且他们意图尽可能互换。如果某些其他Python实现由于某种原因以不同的方式构建async
coros和yield from
coros,它们仍然需要像在CPython中那样可互换(例如,你可以运行{{1为Python 3.4编写的代码。
无论如何,即使这个理由没有在很多单词中的任何地方得到体现,但在Coroutine object methods下的PEP中明确记录了该决定:
协同程序在内部基于生成器,因此它们共享实现。与生成器对象类似,协同程序具有
asyncio
,throw()
和send()
方法。协同作用close()
和StopIteration
扮演相同的角色......
作为讨论GeneratorExit
的一部分,做了的一件事就是异步迭代器无法引发async for
。如果设计以某种方式被更改,因此异步迭代器可以提高它,这将使得无法使用普通生成器构建异步迭代器。因此创建了一个新的异常StopIteration
。此时很明显,实际上并没有一个coro或普通生成器应该明确地引发StopAsyncIteration
,因此PEP 479(它立即应用于异步coros,但在几个版本中有效)对于传统发电机)。请参阅Why StopAsyncIteration
。