[Python-ideas] Possible PEP 380 tweak

Ron Adam rrr at ronadam.com
Sat Oct 30 18:54:15 CEST 2010

On 10/30/2010 02:58 AM, Nick Coghlan wrote:
> On Sat, Oct 30, 2010 at 4:42 PM, Ron Adam<rrr at ronadam.com>  wrote:
>> Ok, after thinking about this for a while, I think the "yield from" would be
>> too limited if it could only be used for consumers that must run until the
>> end. That rules out a whole lot of pipes, filters and other things that
>> consume-some, emit-some, consume-some_more, and emit-some_more.
> Indeed, the "stop-in-the-middle" aspect is tricky, but is the crux of
> what we're struggling with here.
>> I think I figured out something that may be more flexible and insn't too
>> complicated.
> Basically a way to use yield from, while declaring how to force the
> end of iteration? Interesting idea.

Not iteration, iteration can continue.  It signals the end of delegation, 
and returns control to the generator that initiated the delegation.

> However, I think sentinel values are likely a better way to handle
> this in a pure PEP 380 context.

Sentinel values aren't always better because they require a extra 
comparison on each item.

>> Here's an example.
> Modifying this example to use sentinel values rather than throwing in
> exceptions actually makes it all fairly straightforward in a PEP 380
> context. So maybe the moral of this whole thread is really "sentinel
> values good, sentinel exceptions bad".
> # Helper function to finish off a generator by sending a sentinel value
> def finish(g, sentinel=None):
>    try:
>      g.send(sentinel)
>    except StopIteration as ex:
>      return ex.value
> def gtally(end_tally=None):
>    # Tallies numbers until sentinel is passed in
>    count = tally = 0

>    value = object()

Left over from earlier edit?

>    while 1:
>      value = yield
>      if value is end_tally:
>        return count, tally
>      count += 1
>      tally += value

The comparison is executed on every loop.  A try-except would be outside 
the loop.

> def gaverage(end_avg=None):
>    count, tally = (yield from gtally(end_avg))
>    return tally / count
> def main():
>    g = gaverage()
>    next(g)
>    for x in range(100):
>      g.send(x)
>    return finish(g)


More information about the Python-ideas mailing list