On Wed, 03 Mar 2010 15:41:34 -0500
Dave Angel <da...@ieee.org> wrote:

> John wrote:
> > Hi,
> >
> > I just read a few pages of tutorial on list comprehenion and generator 
> > expression.  From what I gather the difference is "[ ]" and "( )" at the 
> > ends, better memory usage and the something the tutorial labeled as "lazy 
> > evaluation".  So a generator 'yields'.  But what is it yielding too?  
> >
> > John
> >
> >   
> A list comprehension builds a whole list at one time.  So if the list 
> needed is large enough in size, it'll never finish, and besides, you'll 
> run out of memory and crash.  A generator expression builds a function 
> instead which *acts* like a list, but actually doesn't build the values 
> till you ask for them.

To append on Dave's explanation, let us a take special case: when the sequence 
is potentially infinite. Imagine you want a function (actually here a 
generator) to yield the sequence of squares of natural without any limit. The 
stop point will happen in the code using the generator. You could write it eg 
like that (this is just sample code):

def squares():
    squares.n = min if min
        while True:
        squares.n += 1
        n = squares.n
        yield n*n
squares.n = 0

Then, you can use it for instance to get the first 9 squares that happen to be 
multiples of 3.

nineTripleSquares = []
for sq in squares():
    if sq%3 == 0:
        nineTripleSquares.append(sq)
        if len(nineTripleSquares) == 9:
            break
print nineTripleSquares
# ==> [9, 36, 81, 144, 225, 324, 441, 576, 729]

A list can hardly be used here, instead of a generator, because we do not know 
how long the list should be so that we get 9 final items.
We can modify squares to give it borders:

def squares(min=None, max=None):
    squares.n = min-1 if (min is not None) else 0
    squares.max = max
    while True:
        squares.n += 1
        n = squares.n
        if (squares.max is not None) and (n > squares.max):
            raise StopIteration
        yield n*n
squares.n = 0

tripleSquares = []
for sq in squares(7,27):
    if sq%3 == 0:
        tripleSquares.append(sq)
print tripleSquares
# [81, 144, 225, 324, 441, 576, 729]

A more object-oriented vaersion would look like:

class Squares(object):
    def __init__(self, min, max):
        self.n = min-1 if (min is not None) else 0
        self.max = max
    def next(self):
        self.n += 1
        n = self.n
        if (self.max is not None) and (n > self.max):
            raise StopIteration
        return n*n
    def __iter__(self):
        return self

tripleSquares = []
for sq in Squares(7,27):
    if sq%3 == 0:
        tripleSquares.append(sq)
print tripleSquares
# ==> same result

This defines a new type of "iterable" objects. When you use "for item in obj" 
on such object, python looks for the magic method __iter__ to find its 
iterator: here, itself. Then it will repetedly call the iterator's next method 
to get each item.


Denis
-- 
________________________________

la vita e estrany

spir.wikidot.com

_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to