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
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to