[Tutor] Iterators and generators for the masses

Paul Sidorsky paulsid@shaw.ca
Mon, 25 Feb 2002 19:46:38 -0700


kevin parks wrote:

> 2> Anyone up to explaining them here? (hopefully in a way that 
> someone other than Tim Peters and Guido understands! Insult me if 
> you must -- talk to me like I am a 12 year old! Why? Because there 
> are 12 year olds out there learning Python and those of us with the 
> math/science/programming chops of a 12 year old who are also trying 
> to understand this stuff).

Okay, here's the simplest non-mathematical example of a generator that I
can think of off the top of my head:

Most of us in North America have seen those "Now Serving" signs.  In
case these aren't common elsewhere, basically what happens is you take a
ticket with a number on it from the dispenser and then wait around until
your number is called.  There's a digital sign on the wall and people
behind the counter can press a button to advance the number on the
sign.  (Usually the numbers are 2-digits, from 00-99.)  This saves
people from having to wait in a queue.

Say you were simulating this in a computer program.  (I don't know why
you would want to, but just say you were.)  The ticket dispenser could
be implemented as a generator.  The dispenser's sole job is to serve up
one number at a time.  We don't care what's going on inside the fat red
circular part, all we are concerned with is that it to give us one
numbered ticket at a time in a predictable order.  This is exactly what
generators do.

As it turns out, the sign can also be implemented using a generator, and
in fact using the same generator as the dispenser.  The principles
behind the sign are the same - it only cares about one number at a time
in a specific order, in this case the same order as the dispenser.

So to implement this we might do something like this:

def ticket_number_gen(start=0, wrap=100):
    num = start
    while 1:
        yield num
        num += 1
        if num == wrap:
            num = 0

This could then be used for both the dispenser and the sign as follows:

dispenser = ticket_number_gen()
sign = ticket_number_gen()
...
dispenser.next()  # Fetches the next "ticket".
...
sign.next()       # Advances the sign.

Why do it this way as opposed to another way?  To be honest, I don't
know.  There's nothing here you couldn't do with a function or a class. 
The only advantage I can see to the above is that you don't have to go
to the trouble of creating a class yet it's somewhat cleaner than a
function-based approach.

To me generators only seem to be useful when there's a ton of possible
values and you only need one at a time.  Combinatorics springs to mind. 
So I'd also be happy to see some explanations of their benefits in
"everyday programming".

Perhaps that's the problem with writing tutorials for generators - if
you want to fit them into a task that's simple enough to help you
understand them, you don't need them.  :-)

> what do they do? what can they do, what tasks do they make easier, 
> what is the simplest possible example, what is a more complex 
> example...etc. & co.

I actually found test_generators, the unit test for generator
functionality, quite informative.  It starts simple and then moves to
some advanced applications.  If nothing else it at least has lots of
examples.  It's in the Python source installation, but if you don't have
that here's a (very long) URL:

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/python/python/dist/src/Lib/test/test_generators.py?rev=1.30&content-type=text/vnd.viewcvs-markup

-- 
======================================================================
Paul Sidorsky                                          Calgary, Canada
paulsid@shaw.ca                        http://members.shaw.ca/paulsid/