I came across the following behaviour. Having used a block of code with the following structure,
try:
tup = tuple(<some_expression> for <_> in <iterator>)
except <SomeException>:
pass
when SomeException
was raised during the generation of the tuple (within the generator expression), the try
-except
block didn't handle it and instead the whole program halted. Why is that so? And is there a way to ensure exceptions encountered in genexpr. are "broadcasted" to the outer scope?
Concrete example
test.py
:
def input_generator():
try:
while True:
for token in input().split():
yield token
except EOFError:
pass
pyIn = input_generator()
def tuple_gen(n: int):
try:
while True:
yield tuple(next(pyIn) for _ in range(n))
except StopIteration:
pass
except ValueError:
pass
if __name__ == "__main__":
for a, b in tuple_gen(2):
print(a, b)
Consider iterating over an instance of the tuple_gen
generator, with an empty file as input (as stdin
). Upon encountering EOF, the pyIn
generator terminates and thus next(pyIn)
raises StopIteration
, but instead of being caught by the except
block, the program halts.
For example, saving an empty test.txt
file (just an empty line) and running this on the (Windows) console
python test.py < test.txt
results in the following Traceback:
Traceback (most recent call last):
File "test.py", line 16, in <genexpr>
yield tuple(next(pyIn) for _ in range(n))
StopIteration
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "test.py", line 24, in <module>
for a, b in tuple_gen(2):
File "test.py", line 16, in tuple_gen
yield tuple(next(pyIn) for _ in range(n))
RuntimeError: generator raised StopIteration
Update
As pointed out in the comments by timgeb, this question explains the issue at hand.