[Tutor] generators and classes

Lloyd Kvam pythontutor at venix.com
Tue Feb 24 09:25:52 EST 2004


Look at SimPy for some generator code with classes that would be hard to
do otherwise.

http://simpy.sourceforge.net/
Home

Marilyn Davis wrote:
> Thank you for this.
> 
> On Tue, 24 Feb 2004, Lloyd Kvam wrote:
> 
> 
>>In the first example, you call list_unique which handles the
>>looping, calls the generator, and returns a list.  The class example
>>puts the looping in the caller and never builds a list.  Put unique
>>and list_unique methods into the class and I think it will work more
>>like the first example.
> 
> 
> I'm just thinking that maybe the generator facility doesn't make sense
> in a class structure --> because the initializing part of the
> generator function belongs in __init__ and then you want the yield to
> be in another function because __init__ isn't allowed to return
> anything.  So, you already have two functions with shared scope so you
> might as well return, skip the next(), and keep things simple.
> 
> I tried to do what you suggest and it gets clumsy (but it works!).
> 
> Maybe you intended something different?
> 
> #! /usr/bin/python2.2
> '''
> Demonstrates generators and the 'yield' keyword in the
> context of a class structure.'''
> 
> from __future__ import generators
> import random
> 
> class Scrambler:
>     '''Generator to deliver randomly chosen values from bot
>     to over_top - 1, delivering each value once only.  To
>     collect the numbers, you make an object and call:
>     object.take.next()'''
>     def __init__(self, bot, over_top):
>         self.bot = bot
>         self.over_top = over_top
>         self.taken = [0] * (over_top - bot)
>         self.take = self.dummy()
> 
>     def dummy(self):
>         while 1:
>             give = random.randrange(self.bot, self.over_top) 
>             if not self.taken[give - self.bot]:
>                 self.taken[give - self.bot] = 1
>                 yield give
> 
> if __name__ == '__main__':
>     scram = Scrambler(0,10)
>     for i in range(10):
>         print scram.take.next()
> 
> #############################
> # OUTPUT:
> # bash-2.05a$ ./scrambler.py
> # 3
> # 4
> # 8
> # 2
> # 7
> # 1
> # 6
> # 0
> # 9
> # 5
> # bash-2.05a$ 
> 
> ----
> 
>>Marilyn Davis wrote:
>>
>>
>>>Hello again,
>>>
>>>I wrote this little program to demonstrate a generator:
>>>
>>>#! /usr/bin/python2.2
>>>'''Function to generate random numbers without repetition.
>>>Demonstrates generators and the 'yield' keyword.'''
>>>
>>>from __future__ import generators
>>>import random
>>>
>>>def unique(bot, over_top):
>>>    '''Generator to deliver randomly chosen values from bot
>>>    to over_top - 1, delivering each value once only.'''
>>>    taken = [0] * (over_top - bot)
>>>    while (1):
>>>        give = random.randrange(bot, over_top) 
>>>        if not taken[give - bot]:
>>>            taken[give - bot] = 1
>>>            yield give
>>>
>>>def list_unique(bot, over_top):
>>>    '''Returns a list of the generated numbers'''
>>>    gen = unique(bot, over_top)
>>>    return [gen.next() for i in range(bot, over_top)]
>>>
>>>if __name__ == '__main__':
>>>    print '(0,5) = ', list_unique(0,5)
>>>    print '(10,21) = ', list_unique(10,21)
>>>
>>>#############################
>>># OUTPUT:
>>># bash-2.05a$ ./unique.py
>>># (0,5) =  [2, 3, 1, 0, 4]
>>># (10,21) =  [17, 10, 18, 20, 19, 15, 11, 13, 12, 16, 14]
>>># bash-2.05a$     
>>>
>>>-----
>>>
>>>But now that I'm preparing to teach OO, I want to do the class
>>>equivalent, which turns out like this:
>>>
>>>#! /usr/bin/env python2.2
>>>
>>>import random
>>>
>>>class NumberHat:
>>>    '''Generator to deliver randomly chosen values from bot
>>>to over_top - 1, delivering each value once only.'''
>>>    def __init__(self, bot, over_top):
>>>        self.bot = bot
>>>        self.over_top = over_top
>>>        self.taken = [0] * (over_top - bot)
>>>
>>>    def take(self):
>>>        while 1:
>>>            give = random.randrange(self.bot, self.over_top) 
>>>            if not self.taken[give - self.bot]:
>>>                self.taken[give - self.bot] = 1
>>>                return give
>>>
>>>if __name__ == '__main__':
>>>    hat = NumberHat(0,10)
>>>    for i in range(10):
>>>        print hat.take()
>>>            
>>>############################################################
>>># OUTPUT:
>>># bash-2.05a$ ./numberhat.py
>>># 1
>>># 5
>>># 6
>>># 9
>>># 3
>>># 7
>>># 0
>>># 8
>>># 2
>>># 4
>>># bash-2.05a$ 
>>>
>>>---
>>>
>>>But there's no generator in it.  Is this natural?  Or is there
>>>some other thought I should be thinking?
>>>
>>>Thank you again and again.
>>>
>>>Marilyn
>>>
>>>
>>>_______________________________________________
>>>Tutor maillist  -  Tutor at python.org
>>>http://mail.python.org/mailman/listinfo/tutor
>>>
>>
>>
> 

-- 
Lloyd Kvam
Venix Corp.
1 Court Street, Suite 378
Lebanon, NH 03766-1358

voice:	603-653-8139
fax:	801-459-9582




More information about the Tutor mailing list