Python PEP479 Change StopIteration handling inside

2019-02-17 01:43发布

问题:

Could someone help me understand what PEP479 is about? I was reading the doc and couldn't get my head around it.

The abstract says:

This PEP proposes a change to generators: when StopIteration is raised inside a generator, it is replaced it with RuntimeError. (More precisely, this happens when the exception is about to bubble out of the generator's stack frame.)

So for example, does a loop like so still work?

it = iter([1,2,3])
try:
    i = next(it)
    while True:
        i = next(it)
except StopIteration:
    pass

Or does it mean that if I have a generator definition like so:

def gen():
    yield from range(5)
    raise StopIteration

the StopIteration is going to be replaced with RuntimeError?

I would really appreciate if someone could shed some light on this.

回答1:

Your first loop should still work -- StopIteration will still be raised when a generator is exhausted.

The difference is that there was ambiguity when a StopIteration was raised in a generator. Did it get raised (implicitly) because the generator ran out of things to yield -- Or did it get raised because a delegate generator ran out of things to yield (maybe due to a next call) and the exception wasn't handled properly? PEP-0479 tries to address that ambiguity. Now if you get a StopIteration, it means that the generator you are working with ran out items to yield. Said another way, it means that a delegate generator didn't get mis-handled when running out of items.

To support this change, your generator should return instead of raising StopIteration explicitly.

def gen():
    yield from range(5)
    return

Here's what happens if you try it with the StopIteration and generator_stop enabled (which will become the default when python3.7 comes around):

>>> from __future__ import generator_stop
>>> def gen():
...     yield from range(5)
...     raise StopIteration
... 
>>> list(gen())
Traceback (most recent call last):
  File "<stdin>", line 3, in gen
StopIteration

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: generator raised StopIteration