15.04.2013 Views

Core Python Programming (2nd Edition)

Core Python Programming (2nd Edition)

Core Python Programming (2nd Edition)

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

11.10. Generators<br />

Earlier in Chapter 8, we discussed the usefulness behind iterators and how they give non-sequence<br />

objects a sequence-like iteration interface. They are simple to understand because they only have one<br />

method, a next() that is called to get the next item.<br />

However, unless you implement a class as an iterator, iterators really do not have much "intelligence."<br />

Would it not be much more powerful to call a function that somehow "generated" the next value in the<br />

iteration and returned with something as simple as a next() call? That is one motivation for generators.<br />

Another aspect of generators is even more powerful ... the concept of coroutines. A coroutine is an<br />

independent function call that can run, be paused or suspended, and be continued or resumed where it<br />

left off. There is also communication between the caller and the (called) coroutine. For example, when a<br />

coroutine pauses, we can receive an intermediate return value from it, and when calling back into one,<br />

to be able to pass in additional or altered parameters, yet still be able to pick up where we last left it,<br />

with all state still intact.<br />

Coroutines that are suspended yielding intermediate values and resumed multiple times are called<br />

generators, and that is exactly what <strong>Python</strong> generators do. Generators were added to <strong>Python</strong> in 2.2 and<br />

made standard in 2.3 (see PEP 255), and although powerful enough, they were significantly enhanced in<br />

<strong>Python</strong> 2.5 (see PEP 342). These enhancements bring generators even closer to being full coroutines<br />

because values (and exceptions) are allowed to be passed back into a resumed function. Also,<br />

generators can now yield control while waiting for a generator it has called to yield a result instead of<br />

blocking to wait for that result to come back before the calling generator can suspend (and yield a<br />

result). Let us take a closer look at generators starting from the top.<br />

What is a generator <strong>Python</strong>-wise? Syntactically, a generator is a function with a yield statement. A<br />

function or subroutine only returns once, but a generator can pause execution and yield intermediate<br />

resultsthat is the functionality of the yield statement, to return a value to the caller and to pause<br />

execution. When the next() method of a generator is invoked, it resumes right where it left off (when it<br />

yielded [a value and] control back to the caller).<br />

When generators were added back in 2.2, because it introduced a new keyword, yield, for backward<br />

compatibility, you needed to import generators from the __future__ module in order to use them. This<br />

was no longer necessary when generators became standard beginning with 2.3.<br />

11.10.1. Simple Generator Features<br />

Generators behave in another manner similar to iterators: when a real return or end-of-function is<br />

reached and there are no more values to yield (when calling next()), a StopIteration exception is<br />

raised. Here is an example, the simplest of generators:<br />

def simpleGen():<br />

yield 1<br />

yield '2 --> punch!'

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!