The Nerdary

Finally, a place where web developers blog.

Generators and the yield keyword

Everywhere I look, generator tutorials are doing a bad job of teaching the material. The reason for this is that generators are taught right from the iteration point of view (for/in).

The problem with this is it doesn’t help the beginner. A better example of generators is to look at them as a result of a sequence of events (step-by-step) instead of in a loop.

This is primarily for Python users (optimally with iPython).

A simple generator

Here is a simple generator function:

def gentastic():
    print("The generator hath begun!")
    yield "All hail the generator"
    print("The generator hath returned!")
    yield "All hail the generator"
    print("The generator is risen!")
    yield "All hail the generator"
    print("The generator hath now ended!")
    yield "It is right to give him thanks and praise"

Is this the most efficient generator? No. Does it love you? Of course it does.

Yield

When you use the yield keyword in a function it returns a generator object (it doesn’t just return that string) and immediately exits the scope it’s in. It yields control to the function that called it with a little gift sometimes. In our case we’re yielding with strings like “All hail the generator!” Those strings get wrapped into the generator object.

To get a better idea type the following:

awesome = gentastic()

Then type awesome again and hit return. You should see something like this:

<generator object gentastic at 0x100462370>

Boom. Generator object. Thanks yield.

Next

A generator object has many methods but the most important one is next.

Let’s manually call next on the previous awesome object:

print(awesome.next())

Here is the output:

The generator hath begun!
All hail the generator

I’m using the print function for a very specific reason. I want to see the string value that the generator object is carrying right away. I could also assign it like q = awesome.next() and it will give me that string (“All hail the generator!”) as the value of q.

Now let’s call the next method again:

print(awesome.next())

and I get this:

The generator hath returned!
All hail the generator

Did you see what happened? Isn’t that fantastic! When we called next() it brought us back into the function at a different starting point (after the previous yield) each time. That’s why yield isn’t a return statement, it remembers! It knows what you did last summer.

Calling awesome.next() again returns:

The generator is risen!
All hail the generator

The grand finale

Now, this is the typical example that follows tutorials on generators:

for a in gentastic():
    print(a)

More on this sequence and using iterables when I’m not feeling incredibly lazy and want to follow-up.

Update: In Python 3 the correct way to call next is not object.next() but rather next(object). Thanks to takluyver.

By Kenny Meyers
December, 7th 2011

Comments

  • Souen said…

    Nice !

    Posted at 05:17 PM on December 08, 2011

  • lahwran said…

    print() is a function in python 3 and print is a statement in python 2. it’s not a method.

    Posted at 09:08 PM on December 08, 2011

  • Kenny Meyers said…

    @Lahwran: Good catch on the wording. I use method, function and sometimes even routine interchangeably sometimes.

    print() as a function has been available since python 2.6 (or at least the print function style) so I see no reason to write about the previous format.

    Posted at 10:15 PM on December 08, 2011

  • lahwran said…

    It is, in fact, not normally a function. that must be explicitly enabled with a __future__ import. use of print(‘asdf’, “blah”) without this future import is actually identical to print (‘asdf’, “blah”) and as such can be used as print[“asdf”, “blah”] or print{“asdf”: “blah”}. This is an important difference and is something that as a beginning I would have found very confusing.

    Do with this information what you wish.

    Posted at 01:37 PM on December 16, 2011

  • lahwran said…

    excuse me, beginner*.

    Posted at 01:37 PM on December 16, 2011

Post a Comment

Commenting is not available in this channel entry.