I'm reading the documentation for Python 3 here:
If a generator code directly or indirectly raises
StopIteration, it is converted into aRuntimeError(retaining theStopIterationas the new exception's cause).
I don't understand that, can anyone explain?
This is what I've tried in Python 3.6, but nothing seems to have been caught:
def gen1():
yield from [1, 2, 3]
raise StopIteration
def gen2():
raise StopIteration
try:
a = list(gen1())
# a == [1, 2, 3]
except RuntimeError:
print("Caught")
try:
a = gen1()
next(a), next(a), next(a), next(a), next(a)
except RuntimeError:
print("Caught")
try:
gen2()
except RuntimeError:
print("Caught")
try:
a = list(gen2())
except RuntimeError:
print("Caught")
Specially, both calls to gen2() raised the StopIteration, but still not converted into RuntimeError.
You missed that this change applies to Python 3.7 and newer. You won't see the conversion in Python 3.6 or older, unless you enable the feature with a
from __future__import first (available as of Python 3.5).From the same page you linked:
PEP 479 -- Change StopIteration handling inside generators further details why this change was made and how it applies. For your code, running on Python 3.7, the output becomes:
Note that I added a
yield 42line togen2()to make it a generator. Withoutyieldoryield fromin the body, you get a regular function instead. Calling a generator function produces a generator object and the function body starts out paused, while calling a normal function executes the body immediately:For Python 3.6, you'd use the
from __future__ import generator_stopcompiler switch (use it at the top of your code when writing a script or module):