On Sat, Nov 22, 2014 at 4:51 AM, Chris Barker firstname.lastname@example.org 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).