generator object or 'send' method?

Aaron Brady castironpi at gmail.com
Wed Feb 11 18:17:11 CET 2009


On Feb 11, 4:41 am, greg <g... at cosc.canterbury.ac.nz> wrote:
> Aaron Brady wrote:
> > It would receive the 'send' from a different point in control
> > flow than its usual 'next'.  Should it repeat a value if it receives a
> > 'send'?
>
> No. This requirement clearly indicates that send() is
> the wrong tool for the job.
>
> I would use a class with a generator as a method, e.g.
>
>    class Multiples:
>
>      m = 1
>
>      def set_multiplier(self, m):
>        self.m = m
>
>      def generate(self, limit):
>        for i in xrange(limit):
>          yield i * self.m
>
>    g = Multiples()
>    for x in g.generate(10):
>      print x
>      if x == 3:
>        g.set_multiplier(42)
>
> produces
>
> 0
> 1
> 2
> 3
> 168
> 210
> 252
> 294
> 336
> 378
>
> --
> Greg

Alright, but you don't have to go so far as to create an entire
class.  It's alright to use a formula.  Here's a way to add a
dictionary to a generator instance.

def gen_dict( fun ):
    def inner( *ar, **kw ):
        self.gen= fun( self, *ar, **kw )
        return self
    class GenWrapper:
        def __iter__( self ): return self
        def __next__( self, *ar, **kw ): return self.gen.__next__
( *ar, **kw )
    self= GenWrapper()
    return inner

It's a shame that you can't set 'self.__next__= self.gen.__next__'.
It costs an entire level of call depth.  On the other hand, I'm not
sure a pure delegate class is possible.

The decorator just puts the generator object in a 'gen' attribute, and
adds itself to the '__init__' argument list.  So the generator has a
'self' argument, which is of type 'instance', and allows dynamic
attributes.

@gen_dict
def jumper( self, N= 1, K= 1 ):
    self.N, self.K= N, K
    while 1:
        yield self.N
        self.N+= self.K

j= jumper()
print( next( j ) )
j.K= 4
print( next( j ) )

It might need some touch-ups to run in Python 2.  Neat mix.  It's a
cool hybrid between Terry's and Greg's idea, and a bare generator.
Unfortunately, if you want 'self' to have any methods, you'll probably
need a class... though maybe it could inherit from 'GenWrapper'.  What
do you think?

P.S.  Here's a slightly simpler version.

def gen_dict( fun ):
    class GenWrapper:
        def __init__( self, *ar, **kw ):
            self.gen= fun( self, *ar, **kw )
        def __iter__( self ): return self
        def __next__( self, *ar, **kw ): return self.gen.__next__
( *ar, **kw )
    return GenWrapper

P.P.S.  Simpler, but a line longer.

class GenWrapper:
    def __init__( self, fun ):
        self.fun= fun
    def __call__( self, *ar, **kw ):
        self.gen= self.fun( self, *ar, **kw )
        return self
    def __iter__( self ): return self
    def __next__( self, *ar, **kw ): return self.gen.__next__( *ar,
**kw )



More information about the Python-list mailing list