[Python-Dev] PEP 380 (yield from a subgenerator) comments

Nick Coghlan ncoghlan at gmail.com
Wed Mar 25 14:22:41 CET 2009


Greg Ewing wrote:
> Would you be happier if some syntactic way to do that
> were provided?
> 
> It could perhaps be done by enhancing the part of the
> 'for' loop that gets executed upon normal termination
> of the iterator.
> 
>   for x in my_iter:
>     do_something_with(x)
>   else v:
>     handle_return_value(v)

I think something like that would actually make the PEP much stronger on
this front - it would promote the idea of a "final value" for iterators
as a more fundamental concept that can be worked with in a non-generator
context.

I'm also reminded of an idea that I believe existed in the early drafts
of PEP 342: using "continue value" to invoke an iterator's send() method
instead of next() as part of a normal for loop.

With those two ideas combined, the PEP's "yield from" expansion could
then look like:

  for x in EXPR:
    _v = yield x
    if _v is not None:
      continue _v
  else _r:
    RESULT = _r

(If "continue None" was defined as invoking .next() instead of
.send(None), then that loop body could be simplified to just "continue
yield x". However, I think it is preferable to keep the bare 'continue'
and dropping off the end of the loop as invoking next(), while "continue
arg" invokes send(None), since the latter form clearly *expects* the
iterator to have a send() method and it is best to emit the
AttributeError immediately if the method isn't there)

Strangely enough, I think proposing a more general change to the
iteration model to include sending values into iterators and having an
accessible "final value" may actually be easier to sell than trying to
sell "yield from" as a pure generator construct with no more general
statement level equivalent. Trying to sell the multi-stage function
iteration model and the concise expression form for invoking them from
another generator all at once is a lot to take in one gulp.

I suspect that angle of attack would also make *testing* this kind of
code far simpler as well. For example:

  for value, send_arg, expected in zip(gf_under_test(),
                                     send_args, expected_values):
    assertEqual(value, expected)
    continue send_arg
  else result:
    assertEqual(result, expected_result)

I'm not actually sure how you would go about writing a test driver for
that example multi-stage function *without* either making some kind of
change to for loops or developing some rather ugly test code.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------


More information about the Python-Dev mailing list