Usually, you communicate with a generator by asking for data with
next(gen). You also can send some values back with
g.send(x) in Python 3. But the technique you probably don't use every day, or maybe even isn't aware of, is throwing exceptions inside a generator.
gen.throw(e) you may raise an exception at the point where the
gen generator is paused, i.e. at the point of some
gen catches the exception,
get.throw(e) returns the next value yielded (or
StopIteration is raised). If
gen doesn't catch the exception, it propagates back to you.
In : def gen(): ...: try: ...: yield 1 ...: except ValueError: ...: yield 2 ...: In : g = gen() ...: In : next(g) Out: 1 In : g.throw(ValueError) Out: 2 In : g.throw(RuntimeError('TEST')) ... RuntimeError: TEST
You can use it to control generator behavior more precisely, not only be sending data to it but by notifying about some problems with values yielded for example. But this is rarely required, and you have a little chance to encounter
g.throw in the wild.
@contextmanager decorator from
contextlib does exactly this to let the code inside the context catch exceptions.
In : from contextlib import contextmanager ...: ...: @contextmanager ...: def atomic(): ...: print('BEGIN') ...: try: ...: yield ...: except Exception: ...: print('ROLLBACK') ...: else: ...: print('COMMIT') ...: In : with atomic(): ...: print('ERROR') ...: raise RuntimeError() ...: BEGIN ERROR ROLLBACK