[Python-ideas] x=(yield from) confusion [was:Yet another alternative name for yield-from]

Jacob Holm jh at improva.dk
Tue Apr 7 04:59:31 CEST 2009


Greg Ewing wrote:
> Jacob Holm wrote:
>
>> No, in the coroutine pattern it absolutely should not. The first 
>> value yielded by the generator of every coroutine is None and should 
>> be thrown away.
>
> That only applies to the *top level* of a coroutine. If
> you factor some code out of a coroutine and call it using
> yield-from, the first value yielded by the factored-out
> code is needed and mustn't be thrown away.

One major reason for factoring something out of a coroutine would be if 
the factored-out code was independently useful as a coroutine. But I 
cannot actually *make* it a coroutine if I want to call it using 
yield-from because it is not always at the "top level".

>
> So I stand by what I said before. If you're using such
> a decorator, you only apply it to the top level generator
> of the coroutine, and you don't call the top level
> using yield-from.
>

So one @coroutine can't call another using yield-from. Why shouldn't it 
be possible? All we need is a way to avoid the first next() call and 
substitute some other value.

Here is a silly example of two coroutines calling each other using one 
of the syntax-based ideas I have for handling this. (I don't care about 
the actual syntax, just about the ability to do this)

@coroutine
def avg2():
    a = yield
    b = yield
    return (a+b)/2

@coroutine
def avg_diff():
    a = yield from avg2() start None  # "start EXPR" means use EXPR for first value to yield instead of next()
    b = yield from avg2() start a     # "start EXPR" means use EXPR for first value to yield instead of next()
    yield b
    return a-b

a = avg2()
a.send(41)
a.send(43)   # raises StopIteration(42)

d = avg_diff()
d.send(1.0)  
d.send(2.0)  # returns from first yield-from, yields 1.5 as part of starting second yield-from
d.send(3.0)
d.send(4.0)  # returns from second yield-from. yields 3.5
d.next()     # returns from avg_diff. raises StopIteration(-2.0)


The important things to note here are that both avg2 and avg_diff are 
independently useful coroutines (yeah ok, not that useful), and that the 
"natural" value to yield from the "d.send(2.0)" line does not come from 
calling next() on the subgenerator, but rather from the outer generator.

I don't think there is any way to achieve this without some way of 
substituting the initial next() call in yield-from.

Regards
- Jacob




More information about the Python-ideas mailing list