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

Jacob Holm jh at improva.dk
Mon Apr 6 15:41:27 CEST 2009

Greg Ewing wrote:
> Jacob Holm wrote:
>> The argument that we have no value to send before we have yielded is 
>> wrong. The generator containing the "yield-from" could easily have a 
>> value to send (or throw)
> No, Guido is right here. You *can't* send a value (other
> than None) into a generator that hasn't reached its first
> yield (try it and you'll get an exception). The first
> call has to be next().

The whole idea of the coroutine pattern is to replace this restriction 
on the caller with a restriction about the first yield in the coroutine. 
This would probably be a lot clearer if the coroutine decorator was 
written as:

def coroutine(func):
    def start(*args,**kwargs):
        cr = func(*args,**kwargs)
        v = cr.next()
        if v is not None:
            raise RuntimeError('first yield in coroutine was not None')
        return cr
    return start

The first call *from user code* to a generator decorated with @coroutine 
*can* be a send() or throw(), and in most cases probably should be.

>> and if iter(EXPR) returns a coroutine or a non-generator it could 
>> easily be ready to accept it.
> If it's ready to accept a send, it must have already
> yielded a value, which has been lost, when it should have
> been yielded to the caller of the delegating generator.

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 

>> Next issue is that the value returned by it.close() is thrown away by 
>> yield-from.
> Since I don't believe that close() should be expected to
> return a useful value anyway, that's not a problem.

It is a problem in the sense that it is surprising behavior. If close() 
doesn't return the value, it should at least raise some exception. I am 
warming to the idea of reraising the StopIteration if it has a non-None 
value. This matches Guidos suggestion for how to retrieve the value 
after a yield-from that was thrown a GeneratorExit. If you insist it is 
an error to return a value as response to GeneratorExit, raise 
RuntimeError. But *please* don't just swallow the value.

- Jacob

More information about the Python-ideas mailing list