At 10:39 PM 3/26/2009 -0500, Guido van Rossum wrote:
That +0 could turn into a +1 if there was a way to flag this as an
error (at runtime), at least if the return is actually executed:

def g():
    yield 42
    return 43

for x in g():
    print x    # probably expected to print 42 and then 43

Perhaps the exception used in this case could be a different exception
than StopIteration? Regular iteration could either just pass this
exception through or explicitly check for it (a single pointer
comparison could usually suffice), depending on whether it would be a
subclass of StopIteration.

Could we at least have some syntax like 'return from yield with 43', to distinguish it from a regular return, clarify that it's returning a value to a yield-from statement, and emphasize that you need a yield-from to call it?

If it doesn't have some sort of variant syntax, the error message for the return exception is going to need to be rather verbose in order to be clear. However, if there is a variant syntax, then an error message like "'return from yield' without 'yield from'" might be clear enough, and we can keep the current error for returning values in generators.

That way, the paired special syntax is clearly identifiable as coroutine/microthread control flow, in a way that's both TOOOWTDI and EIBTI.

One remaining quirk or missing piece: ISTM there needs to be a way to extract the return value without using a yield-from statement. I mean, you could write a utility function like:

   def unyield(geniter):
       try:
           while 1: geniter.next()
       except GeneratorReturn as v:
           return v.value

OTOH, I suppose this function is still a trampoline, just one that doesn't actually do anything except return an eventual exit value. I suppose you could do a slightly improved one thus:

    def unyield(geniter, value=None, func=lambda v: v)
       try:
           while 1: value=func(geniter.send(value))
       except GeneratorReturn as v:
           return v.value

And drop it into itertools or some such. It's sort of like an all-purpose map/reduce for generators, so that all you need to do is pass in a function to do whatever processing you need (e.g. I/O waiting) on the values yielded. You could also use another generator's send() method as the function passed in, in which case you'd basically have a pair of coroutines... and whichever returned a value first would end up as the return value of the overall function. That'd probably be pretty useful for the sort of simple (non I/O) coroutines Greg seems to have in mind.

Or, these could just be examples in the PEP, I suppose. They're not terribly difficult to write... but then I might be biased since I've written a ridiculous number of coroutine trampolines for Python generators over the last how-many-ever years Python has had generators.

_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to