I'm reading the documentation for Python 3 here:
If a generator code directly or indirectly raises
StopIteration
, it is converted into aRuntimeError
(retaining theStopIteration
as 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 42
line togen2()
to make it a generator. Withoutyield
oryield from
in 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_stop
compiler switch (use it at the top of your code when writing a script or module):