Python: Generator Cleanup

This code in this post is in Python 3, but aside from “cosmetic” differences, such as next(g) vs g.next() it applies to Python 2 as well.


This is a companion discussion topic for the original entry at http://amir.rachum.com/blog/2017/03/03/generator-cleanup/

This is one of the reasons why Python moved from “yield” to “await” when implementing coroutines. Yield is not really the right metaphor when you have an event loop, since you don’t yield to the entity that closed you, you yield to the event loop.

Shouldn’t it be like this?

except GeneratorExit:
    closed = True
    raise  # <-- this was missing

@ionelmc you are correct. I fixed it in the post. Thanks!

I would suggest just going with nested try blocks. It’s pretty clear what is going on, although it might not be immediately apparent WHY the code was written this way unless you’re familiar with the problem.

def gen():
    try:
        yield 'so far so good'
        try:
            yield 'yay'
        finally:
            yield 'bye'
    except GeneratorExit:
        raise

You could probably even write a finalyield decorator to add an outer try: ...except GeneratorExit: raise block to any generator, like:

@finalyield
def gen():
    ...

etc etc

Although your post is quite old… what you would like to have (“finally except GeneratorExit”) exists in python:

def safegen():
    try:
        yield 'so far so good'
        yield 'yay'
    except GeneratorExit:
        pass
    else:
        yield 'boo'