本地协程和StopIteration

时间:2018-05-04 01:06:32

标签: python asynchronous

考虑这个简单的协程

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共享重要代码?或者还有其他一些原因?

1 个答案:

答案 0 :(得分:1)

我认为没有人在PEP 492背后的讨论中明确地将此作为明确的设计选择进行讨论,但我认为它们不是只是它们碰巧共享重要的代码,而且他们意图尽可能互换。如果某些其他Python实现由于某种原因以不同的方式构建async coros和yield from coros,它们仍然需要像在CPython中那样可互换(例如,你可以运行{{1为Python 3.4编写的代码。

无论如何,即使这个理由没有在很多单词中的任何地方得到体现,但在Coroutine object methods下的PEP中明确记录了该决定:

  

协同程序在内部基于生成器,因此它们共享实现。与生成器对象类似,协同程序具有asynciothrow()send()方法。协同作用close()StopIteration扮演相同的角色......

作为讨论GeneratorExit的一部分,做了的一件事就是异步迭代器无法引发async for。如果设计以某种方式被更改,因此异步迭代器可以提高它,这将使得无法使用普通生成器构建异步迭代器。因此创建了一个新的异常StopIteration。此时很明显,实际上并没有一个coro或普通生成器应该明确地引发StopAsyncIteration,因此PEP 479(它立即应用于异步coros,但在几个版本中有效)对于传统发电机)。请参阅Why StopAsyncIteration