简体   繁体   中英

Native coroutine and StopIteration

Consider this simple coroutine

In [9]: async def coro():                  
   ...:     print('hello world')           
   ...:

We know that that native coroutines are not iterators

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 

However, if I run a coroutine, I get a StopIteration error.

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 answers that native co-routines are functionally equivalent to generated based coroutines. But another answer for the same question goes further and explains how they serve separate purposes as well.

Is the only reason that native coros raise StopIteration error is that they share significant code with generator based coros? or there is some other reason as well?

I don't think anyone specifically discussed this as an explicit design choice in the discussion behind PEP 492 , but I think it's not just that they happen to share significant code, but also that they're intended to be as interchangeable as possible. If some other Python implementation for some reason built async coros and yield from coros differently, they'd still need to be as interchangeable as they are in CPython (so that, eg, you can run asyncio code written for Python 3.4).

At any rate, even if the rationale isn't enshrined anywhere in so many words, the decision is explicitly documented in the PEP, under Coroutine object methods :

Coroutines are based on generators internally, thus they share the implementation. Similarly to generator objects, coroutines have throw() , send() and close() methods. StopIteration and GeneratorExit play the same role for coroutines…

And one thing that did come up, as part of the discussion of async for , is that an async iterator can't raise StopIteration . And if the design were somehow changed so async iterators could raise it, that would make it impossible to build async iterators with normal generators. So a new exception, StopAsyncIteration was created. At which point it became clear that there is actually no case where a coro or a normal generator should explicitly raise StopIteration , hence PEP 479 (which was applied to async coros immediately, but grandfathered in over a few versions for traditional generators). See Why StopAsyncIteration .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM