On 10/30/2010 02:58 AM, Nick Coghlan wrote:
On Sat, Oct 30, 2010 at 4:42 PM, Ron Adamrrr@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)