in search of graceful co-routines

Ian Kelly ian.g.kelly at gmail.com
Tue May 17 13:26:54 EDT 2011


On Tue, May 17, 2011 at 11:04 AM, Chris Withers <chris at simplistix.co.uk> wrote:
> Now, since the sequence is long, and comes from a file, I wanted the
> provider to be an iterator, so it occurred to me I could try and use the new
> 2-way generator communication to solve the "communicate back with the
> provider", with something like:
>
> for item in provider:
>  try:
>    consumer.handleItem(self)
>  except:
>     provider.send('fail')
>  else:
>     provider.send('succeed')
>
> ..but of course, this won't work, as 'send' causes the provider iteration to
> continue and then returns a value itself. That feels weird and wrong to me,
> but I guess my use case might not be what was intended for the send method.
>
> Anyway, I wonder how other people would write this?
> (I'm particularly interested in a sane way to use the two way communication
> that PEP 342 introduced)

You can use send the way you're wanting to.  It will look something like this:

def provider():
  result = None
  while True:
    if result is None:
      if has_more_items():
        next_item = get_next_item()
      else:
        break
    elif result == 'fail':
      process_fail()
      next_item = None
    elif result == 'succeed':
      process_succeed()
      next_item = None
    else:
      raise ValueError('unknown result %s' % result)
    result = (yield next_item)

Whenever you call provider().next() or provider().send(None), you
simply get the next item.  If you call provider().send('succeed') or
provider().send('fail'), then the corresponding code is run and the
yielded value is None, without consuming anything from the sequence.

Cheers,
Ian



More information about the Python-list mailing list