Path: csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!selfless.tophat.at!newsfeed.xs4all.nl!newsfeed6.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'parameter': 0.05; 'args': 0.07; 'default,': 0.07; 'subject:search': 0.07; 'terry': 0.07; 'twisted,': 0.07; 'variant': 0.07; 'python': 0.08; 'decorator': 0.09; 'none:': 0.09; 'shown.': 0.09; 'throw': 0.09; 'def': 0.12; 'examples': 0.12; 'wrote:': 0.14; 'advance': 0.15; 'arg': 0.16; 'except:': 0.16; 'from:addr:simplistix.co.uk': 0.16; 'from:name:chris withers': 0.16; 'iterator': 0.16; 'message- id:@simplistix.co.uk': 0.16; 'received:89.151': 0.16; 'received:89.151.125': 0.16; 'received:89.151.125.140': 0.16; 'received:server1.simplistix.co.uk': 0.16; 'received:simplistix.co.uk': 0.16; 'reedy': 0.16; 'val': 0.16; 'method.': 0.16; 'cc:addr:python-list': 0.17; 'yield': 0.19; 'cheers,': 0.19; 'header:In-Reply-To:1': 0.21; 'cc:2**0': 0.22; 'cc:no real name:2**0': 0.23; 'closest': 0.23; "doesn't": 0.25; 'certainly': 0.25; 'raise': 0.28; 'skip:_ 20': 0.28; 'mode': 0.29; 'class': 0.29; 'instead': 0.29; 'code,': 0.29; 'bit': 0.30; 'cc:addr:python.org': 0.30; 'considered,': 0.30; 'from:addr:chris': 0.30; 'typeerror:': 0.30; 'print': 0.31; "can't": 0.32; 'cases': 0.32; 'posts': 0.32; 'does': 0.33; "i've": 0.33; 'chris': 0.34; 'file': 0.34; 'however,': 0.34; 'follows:': 0.34; 'that,': 0.34; 'option': 0.35; 'header:User-Agent:1': 0.35; 'skip:" 10': 0.35; 'function.': 0.35; 'itself,': 0.35; 'skip:@ 10': 0.35; 'try:': 0.35; 'using': 0.35; 'none': 0.37; 'feedback': 0.37; 'something': 0.37; 'push': 0.37; 'another': 0.37; 'pretty': 0.37; 'two': 0.37; 'processing': 0.38; 'but': 0.38; 'subject:: ': 0.38; 'received:192': 0.38; 'skip:s 20': 0.39; "i'd": 0.39; 'allows': 0.40; 'received:192.168.1': 0.40; 'more': 0.60; 'url:co': 0.62; 'ready': 0.63; 'believe': 0.66; 'producers': 0.67; 'received:89': 0.68; 'batch': 0.68; 'receive': 0.68; 'reverse': 0.73; 'protect': 0.77; 'seen.': 0.84; 'consumer': 0.85; 'happen:': 0.91 Date: Wed, 18 May 2011 07:00:20 +0100 From: Chris Withers User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.17) Gecko/20110414 Thunderbird/3.1.10 MIME-Version: 1.0 To: Terry Reedy Subject: Re: in search of graceful co-routines References: <4DD2AA99.3010508@simplistix.co.uk> In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: python-list@python.org X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 97 NNTP-Posting-Host: 82.94.164.166 X-Trace: 1305698415 news.xs4all.nl 49039 [::ffff:82.94.164.166]:50654 X-Complaints-To: abuse@xs4all.nl Xref: x330-a1.tempe.blueboxinc.net comp.lang.python:5656 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 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