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

Chris Angelico rosuav at gmail.com
Fri Nov 21 19:28:58 CET 2014


On Sat, Nov 22, 2014 at 4:51 AM, Chris Barker <chris.barker at noaa.gov> wrote:
> Anyway, I just went back and read the PEP, and I'm still confused -- would
> the PEP make generators behave  more like iterator classes, or less like
> them?

Neutral. A generator function, an iterator class, etc, etc, etc,
exists solely to construct an iterator. That iterator has a __next__
method, which either returns a value or raises StopIteration, or
raises some other exception (which bubbles up).

There are two easy ways to write iterators. One is to construct a class:

class Iter:
    def __init__(self): self.x = 0
    def __iter__(self): return self
    def __next__(self):
        if self.x == 3: raise StopIteration
        self.x += 1
        return self.x

Another is to write a generator function:

def gen():
    yield 1
    yield 2
    yield 3

Both Iter and gen are callables which return iterators. Both of them
will produce three integers and then raise StopIteration. Both will,
as is good form for iterators, continue to raise StopIteration
thereafter.

And neither Iter nor gen is, itself, an iterator. One is a class which
constructs iterators. The other is a generator function, which also
constructs iterators. That's all. In Iter.__next__, I wrote code which
chose between "return" and "raise StopIteration" to define its result;
in gen(), I wrote code which chose between "yield" and "return" (in
this case, the implicit return at the end of the function) to define
its result.

The only change made by this proposal is that StopIteration becomes,
in a generator, like any other unexpected exception. It creates a
separation between "iterator protocol" (which is implemented by
__next__) and "generator protocol" (which is written in the body of a
function with 'yield' in it).

ChrisA


More information about the Python-ideas mailing list