Why does this code work well and does not throw exceptions?
def myzip(*args):
iters = [iter(arg) for arg in args]
try:
while True:
yield tuple([next(it) for it in iters])
except StopIteration:
return
for x, y, z in myzip([1, 2], [3, 4], [5, 6]):
print(x, y, z)
But if this line
yield tuple([next(it) for it in iters])
replace by
yield tuple(next(it) for it in iters)
then everything stops working and throws a RuntimeError?
This is a feature introduced in Python 3.5, rather than a bug. Per PEP-479, a
RuntimeErroris re-raised intentionally when aStopIterationis raised from inside a generator so that iterations based on the generator can now only be stopped if the generator returns, at which point aStopIterationexception is raised to stop the iterations.Otherwise, prior to Python 3.5, a
StopIterationexception raised anywhere in a generator will stop the generator rather than getting propagated, so that in case of:The former would get a truncated result if
F(x)raises aStopIterationexception at some point during the iteration, which makes it hard to debug, while the latter would propagate the exception raised fromF(x). The goal of the feature is to make the two statements behave the same, which is why the change affects generators but not list comprehensions.