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

Jacob Holm jh at improva.dk
Wed Apr 8 14:39:04 CEST 2009


Nick Coghlan wrote:
> Jacob Holm wrote:
>   
>> That would have been correct if my statement about what was needed
>> wasn't missing a bit.  What you actually need to replace with is
>> something like:
>>
>> def example(start, *args, **kw):
>>    ...
>>    if 'throw' in start:
>>        raise start['throw'] # simulate a throw() on first next()
>>    elif 'send' in start:
>>        x = start['send']    # simulate a send() on first next()
>>    else:
>>        x = yield start.get('yield')  # use specified value for first next()
>>     
>
> This elaboration strikes me as completely unecessary, since next() or
> the equivalent send(None) are the only legitimate ways to start a generator:
>
>   
Correct, but missing the point.  Maybe I explained the "throw" and 
"send" parts badly.  The point is that the following two examples have 
the same effect:

g = example({'send':42})
g.next()

g = example({})
g.next()
g.send(42)


Same effect meaning same last value returned and same internal state.  
You can't do this by just providing a value to yield on the first 
next().  The modified parser example I sent to Greg shows that there is 
a use case for it (although it is written using one of the syntax-based 
ideas). 

> For the PEP, I think the solution to this issue is a couple of conventions:
>
> 1. Either don't implicitly call next() when creating coroutines or else
> make that behaviour easy to bypass). This is a bad idea for the same
> reason that implicitly calling start() on threads is a bad idea:
> sometimes the user will want to separate definition from activation, and
> it is a pain when the original author makes that darn near impossible in
> order to save one line in the normal case.
>   

I don't agree that it is a bad idea to call next automatically.  I can 
see that it is necessary to keep a version around that doesn't do it, 
but that is because of limitations in yield-from.

> 2. Coroutines intended for use with yield-from should take a "start"
> argument that is used for the value of their first yield. This allows
> coroutines to be nested without introducing spurious "None" values into
> the yield stream.
>   

For the coroutine writer, it is just as easy to write:

x = yield start


As it is to write:

x = yield from cr_init(start)


The difference is that the second version is much more useful in yield-from.

Even assuming every relevant object implemented the pattern I suggest, 
it is still not possible to use yield-from to write something like 
itertools.dropwhile and have it delegate all send and throw calls 
correctly.  To make that possible, you need exactly the same thing that 
you need for pre-started coroutines: The ability to replace the next() 
call made by the yield-from expression with something else.  Give me 
that, and you will also have removed the need for a special pattern for 
coroutines that should be usable with yield-from.

Still-hoping-to-avoid-the-need-for-a-special-pattern-ly yours
- Jacob



More information about the Python-ideas mailing list