0

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.

Community
  • 1
  • 1
Anakhand
  • 2,838
  • 1
  • 22
  • 50
  • Could you make your concrete example... concreter? Such that it is runnable and shows the behavior you are trying to showcase here. – timgeb Dec 09 '18 at 20:32
  • @timgeb Yes, I should have done that before. Is the example provided sufficient? – Anakhand Dec 09 '18 at 20:59
  • Ah. You are not catching the `RuntimeError`. – timgeb Dec 09 '18 at 21:04
  • @timgeb Oh, I see. But why does `StopIteration` get "transformed" into a generic `RuntimeError`? – Anakhand Dec 09 '18 at 21:06
  • 2
    I think [this](https://stackoverflow.com/questions/37707187/python-pep479-change-stopiteration-handling-inside-generators) should solve the issue. – timgeb Dec 09 '18 at 21:06

0 Answers0