[Python-ideas] PEP 479: Change StopIteration handling inside generators

Steven D'Aprano steve at pearwood.info
Thu Nov 20 01:25:47 CET 2014


On Thu, Nov 20, 2014 at 02:45:27AM +1000, Nick Coghlan wrote:

> The part I found most compelling was when you pointed out that in the
> special method implementations, the normal return path was always spelled
> with "return", while the "value missing" result was indicated with a
> special kind of exception (StopIteration, AttributeError, IndexError or
> KeyError), and then any other exception was consider unexpected.
> 
> Generators add the third notion of being able to suspend execution via
> "yield", which then left them with two different ways of spelling
> termination inside the frame: "return" OR "raise StopIteration". The second
> spelling ("raise StopIteration") is then inherently surprising, as it's
> entirely redundant, *except* in that it allows you to effectively have a
> "hidden return" in a generator frame that can't be done anywhere else.

I'm not sure that many people outside of this and the python-dev mailing 
lists would find the use of "raise StopIteration" surprising. Rather, I 
expect that they will find the use of an explicit "return" inside a 
generator surprising. People are informally taught that generators use 
yield *instead of* return, so seeing both in the same function is a 
surprise. (Most generators quitely fall out the bottom with no explicit 
end.)


I don't claim that doing so is Pythonic or even good practice, but I am 
sure that there are a lot of people who believe that raising 
StopIteration to exit a generator is (1) supported and (2) preferred.

Examples of code in the wild using StopIteration to exit:


http://code.openhub.net/file?fid=ezlejSoT2q7PWrhgNkpdU55MWOA&cid=jVcYOxnQhvU&s=raise%20StopIteration&fp=301369&mp&projSelected=true#L0

http://code.openhub.net/file?fid=M0gWWCpn-avqHO_jnsYcG2T81lg&cid=VKn_M0_GgKM&s=raise%20StopIteration&fp=301283&mp&projSelected=true#L0

http://code.openhub.net/file?fid=pDrrTI8lyh0LO_6rTCk9npC96SE&cid=Y8jg8v1AyqU&s=raise%20StopIteration&fp=41191&mp&projSelected=true#L0

http://code.openhub.net/file?fid=PTjGrE_5rOhyZhL1CUrPBtRk7n8&cid=tWtPpAs4E1g&s=raise%20StopIteration&fp=210789&mp&projSelected=true#L0

http://code.openhub.net/file?fid=WzkucGktJhjsP8cj4BO6Wcnbx-0&cid=fsj7E8vdVMA&s=raise%20StopIteration&fp=401086&mp&projSelected=true#L0

http://stackoverflow.com/questions/6784934/python-yield-and-stopiteration-in-one-loop

http://stackoverflow.com/questions/14183803/in-pythons-generators-what-is-the-difference-between-raise-stopiteration-and

That last example not only uses raise to exit the generator, but the 
author actually guesses that it is the more Pythonic way to do so.

Here is a description of the generator protocol which could easily lead 
the reader to conclude that raising StopIteration is the correct way to 
exit a generator:

    To support this protocol, functions with yield statement 
    are compiled specially as generators. They return a generator 
    object when they are called. The returned object supports the 
    iteration interface with an automatically created __next__() 
    method to resume execution. Generator functions may have a 
    return simply terminates the generation of values by raising 
    a StopIteration exceptions after any normal function exit. 

http://www.bogotobogo.com/python/python_generators.php


At this point, I'm convinced that there is a good argument for a 
__future__ import changing this behaviour. But I suspect that making 
this the default behaviour in the future will break a lot of code.



-- 
Steven


More information about the Python-ideas mailing list