[Python-Dev] patch: try/finally in generators

Guido van Rossum guido@python.org
Mon, 29 Jul 2002 16:30:36 -0400


> I'm pretty sure it can be made to work (at least for CPython).  The
> proposed patch is not correct since it doesn't handle "finally" code
> that creates a new reference to the generator.

As Oren pointed out, how can you create a reference to the generator
when its reference count was 0?  There can't be a global referencing
it, and (unlike __del__) you aren't getting a pointer to yourself.

> Also, setting the instruction pointer to the return statement is
> really ugly, IMO.

Agreed. ;-)

> There could be valid code out there that does not end with
> LOAD_CONST+RETURN.

The current code generator always generates that as the final
instruction.  But someone might add an optimizer that takes that out
if it is provably unreachable...

> Those are minor details though.  We need to decide if we really want
> this.  For example, what happens if 'yield' is inside the finally block?
> With the proposed patch:
> 
>     >>> def f():
>     ...   try:
>     ...     assert 0
>     ...   finally:
>     ...     return 1
>     ... 
>     >>> f()
>     1
>     >>> def g():
>     ...   try:
>     ...     assert 0
>     ...   finally:
>     ...     yield 1
>     ... 
>     >>> list(g())
>     Traceback (most recent call last):
>       File "<stdin>", line 1, in ?
>       File "<stdin>", line 3, in g
>     AssertionError
> 
> Maybe some people whould expect [1] in the second case.

The latter is not new; that example has no yield in the try clause.
If you'd used a for loop or next() calls, you'd have noticed the yield
got executed normally, but following next() call raises
AssertionError.

But this example behaves strangely:

>>> def f():
...  try:
...   yield 1
...   assert 0
...  finally:
...   yield 2
... 
>>> a = f()
>>> a.next()
1
>>> del a
>>>

What happens at the yield here?!?!  If I put prints before and after
it, the finally clause is entered, but not exited.  Bizarre!!!

--Guido van Rossum (home page: http://www.python.org/~guido/)