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

Wolfgang Maier wolfgang.maier at biologie.uni-freiburg.de
Mon Nov 24 23:53:11 CET 2014


On 15.11.2014 10:29, Chris Angelico wrote:
> PEP: 479
> Title: Change StopIteration handling inside generators
> Version: $Revision$
> Last-Modified: $Date$
> Author: Chris Angelico <rosuav at gmail.com>
> Status: Draft
> Type: Standards Track
> Content-Type: text/x-rst
> Created: 15-Nov-2014
> Python-Version: 3.5
> Post-History: 15-Nov-2014
>
>
> Abstract
> ========
>
> This PEP proposes a semantic change to ``StopIteration`` when raised
> inside a generator, unifying the behaviour of list comprehensions and
> generator expressions somewhat.
>
>
> Rationale
> =========
>
> The interaction of generators and ``StopIteration`` is currently
> somewhat surprising, and can conceal obscure bugs.  An unexpected
> exception should not result in subtly altered behaviour, but should
> cause a noisy and easily-debugged traceback.  Currently,
> ``StopIteration`` can be absorbed by the generator construct.
>
>
> Proposal
> ========
>
> If a ``StopIteration`` is about to bubble out of a generator frame, it
> is replaced with some other exception (maybe ``RuntimeError``, maybe a
> new custom ``Exception`` subclass, but *not* deriving from
> ``StopIteration``) which causes the ``next()`` call (which invoked the
> generator) to fail, passing that exception out.  From then on it's
> just like any old exception. [3]_
>

Now that this PEP is going to be accepted, I'm not sure how much sense 
it still makes to suggest an amendment to it, but anyway:

As stated in the abstract one of the goals of the PEP is to unify 
further the behaviour of comprehensions and generator expressions.

With the PEP in place the following example (taken from Steven 
d'Aprano's post on python-list):

iterable = [iter([])]
list(next(x) for x in iterable)

would raise an error just like

[next(x) for x in iterable]

already does today.

However the comprehension currently raises StopIteration, while the 
proposed error for the generator expression would be of a different 
class (supposedly RuntimeError) - so comprehensions and generator 
expressions would still behave a bit (though much less) differently.

In addition, the PEP leaves an iterator's __next__() method as the only 
reasonable place where user-code should raise StopIteration.
So I would like to argue that instead of just turning StopIteration into 
some other error when it's about to bubble out of a generator frame, it 
should be converted whenever it bubbles out of *anything except an 
iterator's __next__()*. This would include comprehensions, but also any 
other code.

(On the side, I guess the current form of the PEP does address 
hard-to-debug bugs caused by nested generators, but what about nested 
__next__ in iterators ? Shouldn't it using the same logic also be an 
error if a next call inside a __next__ method raises an uncaught 
StopIteration ?)

I think such general behavior would make it much clearer that 
StopIteration is considered special and reserved for the iterator 
protocol. Of course, it might mean more broken code if people use 
StopIteration or a subclass for error signaling outside 
generator/iterators, but this PEP will mean backwards incompatibility 
anyway so why not go all the way and do it consistently.

I'm not sure I'd like the pretty general RuntimeError for this (even 
though Guido favors it for simplicity), instead one could call it 
UnhandledStopIteration ?
I imagine that a dedicated class would help in porting, for example, 
python2 code to python3 (which this PEP does not really simplify 
otherwise) since people/scripts could watch out for something specific ?

Thoughts?
Wolfgang





More information about the Python-ideas mailing list