Suppose that you have the Python try:/finally: problem and need to get around it, specifically you need to both be a generator and have your
finally:
run immediately. Taken from here , one answer is:
def foo(bar):
try:
def output():
... compute with bar ...
yield res
...
return output()
finally:
print "finalizing"
(Now, there is a lot of things that this doesn't help with; the actual computation hasn't finished, so you can't do anything in the
finally:
that would destroy its ability to work.)
I find this confusing enough that it's worthwhile walking through why it works. It goes like this:
The
output()
function is two things; it is both a generator and a closure. As a closure, it captures the arguments that
foo()
was called with, so that it can do computation with them. As a generator, calling it doesn't run any of its code but instead causes Python to immediately return an iterator object that is in turn effectively capturing the output() closure. The
foo()
function then returns this iterator object and as part of returning, executes its own
finally:
clause.
(The shorter way of putting this is that returning the result of calling a generator function does not make you a generator function yourself, and thus your
finally:
will run normally and immediately.)
Obviously, you don't have to move all of the code into the
output()
closure. In some situations you might have a lot of things that you do before you can return the first result, and the more you do in the main function the more resources you can release when it returns.