[Python-ideas] Revised**10 PEP on Yield-From

Jacob Holm jh at improva.dk
Wed Apr 15 12:53:52 CEST 2009


Hi Greg

A few comments on the latest PEP 380 version (rev11d)...

1) IIRC, the use of sys.exc_info() is not needed in 3.x as all 
exceptions have a __traceback__ attribute.

2) The expansion is not handling StopIterations raised as a result of 
calling _i.throw().  They should be treated just like any other 
StopIteration that ends the yield-from.

A simpler expansion based on 1) and 2) but otherwise identical is:

    _i = iter(EXPR)
    try:
        _y = next(_i)
        while 1:
            try:
                _s = yield _y
            except GeneratorExit:
                _m = getattr(_i, 'close', None)
                if _m is not None:
                    _m()
                raise
            except BaseException as _e:
                _m = getattr(_i, 'throw', None)
                if _m is not None:
                    _y = _m(_e)
                else:
                    raise
            else:
                if _s is None:
                    _y = next(_i)
                else:
                    _y = _i.send(_s)
    except StopIteration as _e:
        _r = _e.value
    RESULT = _r


3) If the subiterator has a close() but doesn't have throw() it won't be 
closed when throw() is called on the outer generator.  This is fine with 
me, I am just not sure if it is intentional.

4) If the subiterator has a close() but doesn't have send() it won't be 
closed when a send() on the outer generator causes an AttributeError in 
the expansion.  Again this is fine with me, I am just not sure if it is 
intentional.

5) The last paragraph in the "Use of StopIteration to return values" 
section, seems to be a leftover from an earlier draft of the PEP that 
used a different exception.

6) Several of the issues we have been discussing on python-ideas are not 
mentioned at all:

    * The "initial next()" issue should at least be described and listed
      as out of scope.
    * The "what should close() do if it catches StopIteration with a
      value" issue I don't think we have resolved either way.  Since we
      are not going to store the value, only the first close() would be
      able to return it.  Under those conditions, I no longer think that
      returning the value is a good idea.  If we are not storing or
      returning the value, I think close() should raise an exception. 
      Either reraise the StopIteration, so that the caller has a chance
      to get the value that way, or raise a RuntimeError, because it is
      meaningless to return a value as response to a GeneratorExit when
      that value cannot later be accessed by anything and it is
      therefore most likely a bug.
    * The special-casing of StopIteration should probably be mentioned
      as a rejected idea.  Not special-casing it does break the
      refactoring principle, and I think it important to mention that in
      some way.
    * There may be other issues I have forgotten at the moment.

7) By not mentioning caching, you are effectively saying the methods 
won't be cached.  I have exactly one use for this.  The fastest 
pure-python "full" workaround I can find for the "initial next()" issue 
is a wrapper using Nicks self-modifying class hack.  With this the 
delegation cost is less than 1/3 of any other approach I have tried. 
(But still 13 times higher than a yield-from without the wrapper when 
using your patch).  All that means is that adding caching later would be 
likely to break some code that relied on the exact semantics as 
described in the PEP.

Other than that, everything looks fine.

Best regards
- Jacob



More information about the Python-ideas mailing list