[Python-ideas] Yield-From: Finalization guarantees

Jacob Holm jh at improva.dk
Sun Mar 29 17:47:23 CEST 2009


Jacob Holm wrote:
>
> Would it be possible to attach the current exception (if any) to the 
> StopIteration/GeneratorReturn raised by a return statement in a 
> finally clause? (Using the __traceback__ and __cause__ attributes from 
> PEP-3134) Then the PEP expansion could check for and reraise the 
> attached exception.

Based on that idea, here is the 3.0-based expansion I propose:

_i = iter(EXPR)
try:
    _t = None
    _y = next(_i)
    while 1:
        try:
            _s = yield _y
        except BaseException as _e:
            _t = _e
            _m = getattr(_i, 'throw', None)
            if _m is None:
                raise
            _y = _m(_t)
        else:
            _t = None
            if _s is None:
                _y = next(_i)
            else:
                _y = _i.send(_s)
except StopIteration as _e:
    if _e is _t: 
        # If _e is the exception that we have just thrown to the subiterator, reraise it.
        if _m is None:
            # If there was no "throw" method, explicitly close the iterator before reraising.
            _m = getattr(_i, 'close', None)
            if _m is not None:
                _m()
        raise
    if _e.__cause__ is not None:
        # If the return was from inside a finally clause with an active exception, reraise that exception.
        raise _e.__cause__
    # Normal return
    RESULT = _e.value


I have moved the code around a bit to use fewer try blocks while 
preserving semantics, then removed the check for GeneratorExit and added 
a different check for __cause__.

Even if the __cause__ idea is shot down, I think I prefer the way this 
expansion reads. It makes it easier to see at a glance what is part of 
the loop and what is part of the cleanup.

What do you think?

- Jacob



More information about the Python-ideas mailing list