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.