send() to a generator in a "for" loop with continue(val)??

Aaron Brady castironpi at gmail.com
Fri Apr 17 22:07:23 EDT 2009


On Apr 17, 3:59 pm, Dale Roberts <goobe... at gmail.com> wrote:
> I've started using generators for some "real" work (love them!), and I
> need to use send() to send values back into the yield inside the
> generator. When I want to use the generator, though, I have to
> essentially duplicate the machinery of a "for" loop, because the "for"
> loop does not have a mechanism to send into the generator. Here is a
> toy example:
>
> def TestGen1():
>     for i in xrange(3):
>         sendval = yield i
>         print "   got %s in TestGen()" % sendval
>
> g = TestGen1()
> sendval = None
> try:
>     while True:
>         val = g.send(sendval)
>         print 'val in "while" loop %d' % val
>         sendval = val * 10
> except StopIteration: pass
>
> I have to explicitly create the generator with an assignment, send an
> initial None to the generator on the first go, then have to catch the
> StopIteration exception. In other words, replicate the "for"
> mechanism, but use send() instead of next().
>
> It would be nice if I could just do this instead:
>
> for val in TestGen1():
>     print 'val in "for" loop %d' % val
>     continue(val*10)
>
> ...or something similar. Is this an old idea? Has it been shot down in
> the past already? Or is it worth pursuing? I Googled around and saw
> one hit here:http://mail.python.org/pipermail/python-ideas/2009-February/003111.html,
> but not much follow-up.
>
> I wonder if people want to keep the idea of an "iterator" style
> generator (where send() is not used) separate from the idea of a "co-
> routine" style generator (where send() is used). Maybe combining the
> two idioms in this way would cause confusion?
>
> What do folks think?
>
> dale

You can do it with a wrapping generator.  I'm not sure if it
interferes with your needs.  It calls 'next' the first time, then just
calls 'send' on the parameter with the value you send it.

>>> def genf( ):
...     x= True
...     for _ in range( 10 ):
...             i= yield( x )
...             if i is None:
...                     i= not x
...             x= i
...
>>> def for_send( gen ):
...     x= next( gen )
...     while 1:
...             x= yield( x )
...             x= gen.send( x )
...
>>> a= for_send( genf( ) )
>>> i= 0
>>> for x in a:
...     print( i, x )
...     i+= 1
...     if not i% 3:
...             _= a.send( False )
...
0 True
1 False
2 True
3 True
4 False
5 True
6 True
7 False

As you can see, it skips a beat every third iteration as directed.



More information about the Python-list mailing list