[Python-Dev] Re: [Python-iterators] Python generators and try/finally..

Tim Peters tim.one@home.com
Mon, 14 Jan 2002 19:18:40 -0500


[Neil Schemenauer]
> ...
> In practice, I think the current restriction is not a big problem.
> try/finally is allowed in code that calls generators as well as code
> called by generators.  It is only disallowed in the body of generator
> itself.

It's not that severe, Neil:  the only restriction is that yield cannot
appear in the try clause of a try/finally construct.  try/finally can
otherwise be used freely inside generators, and yield can be used anywhere
inside a generator inside try/except/else, and even in a finally clause
(these latter assuming the yield is not also in the try clause of an
*enclosing* try/finally construct) -- just not in a try/finally's try
clause.

Here's the example from PEP 255 (also embedded in a test_generators.py
doctest, so we know for sure it works as advertised <wink>):

   >>> def f():
    ...     try:
    ...         yield 1
    ...         try:
    ...             yield 2
    ...             1//0
    ...             yield 3  # never get here
    ...         except ZeroDivisionError:
    ...             yield 4
    ...             yield 5
    ...             raise
    ...         except:
    ...             yield 6
    ...         yield 7     # the "raise" above stops this
    ...     except:
    ...         yield 8
    ...     yield 9
    ...     try:
    ...         x = 12
    ...     finally:
    ...         yield 10
    ...     yield 11
    >>> print list(f())
    [1, 2, 4, 5, 8, 9, 10, 11]
    >>>

[David Jeske]
>> The PEP says that there is no guarantee that next() will be called
>> again. However, there is a guaratee that either next() will be called,
>> or the Generator will be cleaned up.

Not so:  Python doesn't guarantee destructors will get called by magic (see
the discussion of __del__ in the Python Reference Manual).  So best practice
is to use explicit (e.g.) close() calls anyway, and if you make your
generator a method of an object, its critical resources can (conveniently,
even!) be exposed to other methods for explicit cleanup (or its __del__, if
you absolutely must).

In practice (and I've had a lot <wink>), I have yet to be so much as midly
annoyed by this restriction.  So I have to echo Neil:

> We should not propagate that behavior without some careful thought.  I
> would like to see some compelling arguments as to why try/finally
> should be supported inside generators.

And especially with bizarre "and 'finally' will probably get executed, but
no guarantee that it will, and there's no predicting when-- or even in which
thread --if it does, and if it does and 'finally' itself goes boom, we may
also ignore the error" semantics.  As the PEP says, all of that is too much
a violation of finally's pre-generators contract to bear.

you-broke-it-you-fix-it<wink>-ly y'rs  - tim