[Python-ideas] Yield-From: Finalization guarantees

Ron Adam rrr at ronadam.com
Fri Apr 3 07:58:40 CEST 2009



Guido van Rossum wrote:
> On Thu, Apr 2, 2009 at 5:35 PM, Ron Adam <rrr at ronadam.com> wrote:
>>
>> Jacob Holm wrote:
>>
>>> That might be the prevailing wisdom concerning GeneratorExit, at least
>>> partly based on the fact that the only way to communicate anything useful
>>> out of a closing generator is to raise another exception.   Thinking a bit
>>> about coroutines, it would be nice to use "send" for the normal
>>> communication and "close" to shut it down and getting a final result.
>>>  Example:
>>>
>>> def averager():
>>>   count = 0
>>>   sum = 0
>>>   while 1:
>>>       try:            val = (yield)
>>>       except GeneratorExit:
>>>           return sum/count
>>>       else:
>>>           sum += val
>>>           count += 1
>>>
>>> avg = averager()
>>> avg.next() # start coroutine
>>> avg.send(1.0)
>>> avg.send(2.0)
>>> print avg.close()  # prints 1.5
>>>
>>>
>>> To do something similar today requires either a custom exception, or the
>>> use of special values to tell the generator to yield the result.  I find
>>> this version a lot cleaner.
>> This doesn't seem less cleaner than the above to me.
>>
>> def averager():
>>    sum = 0
>>    count = 0
>>    try:
>>        while 1:
>>            sum += yield
>>            count += 1
>>    finally:
>>        yield sum / count
>>
>> avg = averager()
>> avg.next()
>> avg.send(1.0)
>> avg.send(2.0)
>> print avg.next()   # prints 1.5
> 
> But your version isn't clean -- it relies on "sum += yield" raising a
> TypeError when yield returns None (due to .next() being the same as
> .send(None)).

Something I noticed is that function and method calls use TypeError in 
cases where the argument count is miss matched.  If there was a different 
exception for miss matched arguments and .next() sent no arguments, it 
could be rewritten in a somewhat cleaner way.

def averager():
     sum = 0
     count = 0
     try:
         while 1:
             sum += yield
             count += 1
     except ArgumentCountError:
         yield sum / count

avg = averager()
avg.next()
avg.send(1.0)
avg.send(2.0)
print avg.next()   # prints 1.5

This seems to me that a different exception for miss-matched arguments 
might be useful in a more general way.


> That's not to say I like Jacob's version that much, but I now
> understand his use case. I note that Dave Beazley works around this
> carefully in his tutorial (dabeaz.com/coroutines/) by using examples
> that produce output on stdout -- and much later, in his multitasking
> schedule example, his trampoline actually interprets yielding a value
> that is neither a SystemCall instance nor a generator as a return from
> a generator. (This is similar to the abuse that your example is giving
> yield, actually.) I'll have to ponder this more.

Yes, generators seem very limiting to me.  Generators with more complex 
input and output requirements are bound to have added complexities to 
offset the limits of a single sequential i/o channel.


> __________
> PS. Somehow the headers in your email made my reply add this:
> 
>   Python-Ideas <public-python-ideas-+ZN9ApsXKcEdnm+yROfE0A at ciao.gmane.org>,
> Nick Coghlan <public-ncoghlan-Re5JQEeQqe8AvxtiuMwx3w at ciao.gmane.org>
> 
> Whoever did that, and whatever they did to cause it, please don't do it again.

I'll manually remove the extra email address's until I (or someone else) 
can explain why they do that.  I hope that's enough for now.

I read several python groups though gmane using Thunderbird on Ubuntu, 
Python-ideas is the only one the email address's are changed like that. (?)

Ron









More information about the Python-ideas mailing list