[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