in search of graceful co-routines
Chris Withers
chris at simplistix.co.uk
Wed May 18 02:00:20 EDT 2011
On 18/05/2011 03:10, Terry Reedy wrote:
> By default, Python iterators operate in pull mode -- consumers request a
> new item when they want one. I believe .send was mostly intended to
> reverse that, to operate in push mode where producers .send() a item to
> a consumer when they are ready to. That is certainly true of examples I
> have seen.
My first exposure was with the @inlineCallbacks decorator in twisted,
which does use it both ways...
> Using .send for feedback to a provider is trickier, as the two other
> posts have shown.
The closest I've found to something graceful is:
def mygenerator(*args):
for arg in args:
print "yielding:",arg
result = yield arg
print "returned:",result
if result is not None:
yield None
provider = mygenerator(1,2,3)
for arg in provider:
print "got:",arg
if arg%2:
provider.send('hello')
However, if you do g.send(None), you still get a result back, which
feels a bit weird...
It's pretty disappointing that neither the send nor throw methods added
as part of PEP342 were provided with a parameter or variant that did
"send an item but don't advance the generator".
> Another option is to write an iterator class instead
> of generator function. You can then give the provider a message receive
> method (.send or whatever) that is decoupled from the send-next method.
Yes, that's an option I'd considered, however, with a provider class as
follows:
class Provider:
def __init__(self,*args):
self.args = args
self.current = 0
def next(self):
try:
val = self.args[self.current]
except:
raise StopIteration()
self.current += 1
print "yielding:",val
return val
def send(self,value):
print "returned:",value
def __iter__(self):
return self
provider = Provider(1,2,3)
for arg in provider:
print "got:",arg
if arg%2:
provider.send('hello')
...but that's a lot more code, and allows one of my anti-use cases to
happen:
provider = Provider(1,2,3)
provider.send("don't want this to be possible")
The generator implementation deals with the above specific case:
File "test.py", line 12, in <module>
provider.send('hello')
TypeError: can't send non-None value to a just-started generator
...which is, in itself, a little weird, given that it doesn't protect
against:
provider = Provider(1,2,3)
val = provider.next()
provider.send("don't want this to be possible")
provider.send("don't want this to be possible")
cheers,
Chris
--
Simplistix - Content Management, Batch Processing & Python Consulting
- http://www.simplistix.co.uk
More information about the Python-list
mailing list