Online Book Reader

Home Category

Learning Python - Mark Lutz [275]

By Root 1944 0
the for, call the generator function directly:

>>> x = gensquares(4)

>>> x

You get back a generator object that supports the iteration protocol we met in Chapter 14—the generator object has a __next__ method that starts the function, or resumes it from where it last yielded a value, and raises a StopIteration exception when the end of the series of values is reached. For convenience, the next(X) built-in calls an object’s X.__next__() method for us:

>>> next(x) # Same as x.__next__() in 3.0

0

>>> next(x) # Use x.next() or next() in 2.6

1

>>> next(x)

4

>>> next(x)

9

>>> next(x)

Traceback (most recent call last):

...more text omitted...

StopIteration

As we learned in Chapter 14, for loops (and other iteration contexts) work with generators in the same way—by calling the __next__ method repeatedly, until an exception is caught. If the object to be iterated over does not support this protocol, for loops instead use the indexing protocol to iterate.

Note that in this example, we could also simply build the list of yielded values all at once:

>>> def buildsquares(n):

... res = []

... for i in range(n): res.append(i ** 2)

... return res

...

>>> for x in buildsquares(5): print(x, end=' : ')

...

0 : 1 : 4 : 9 : 16 :

For that matter, we could use any of the for loop, map, or list comprehension techniques:

>>> for x in [n ** 2 for n in range(5)]:

... print(x, end=' : ')

...

0 : 1 : 4 : 9 : 16 :

>>> for x in map((lambda n: n ** 2), range(5)):

... print(x, end=' : ')

...

0 : 1 : 4 : 9 : 16 :

However, generators can be better in terms of both memory use and performance. They allow functions to avoid doing all the work up front, which is especially useful when the result lists are large or when it takes a lot of computation to produce each value. Generators distribute the time required to produce the series of values among loop iterations.

Moreover, for more advanced uses, generators can provide a simpler alternative to manually saving the state between iterations in class objects—with generators, variables accessible in the function’s scopes are saved and restored automatically.[44] We’ll discuss class-based iterators in more detail in Part VI.

Extended generator function protocol: send versus next

In Python 2.5, a send method was added to the generator function protocol. The send method advances to the next item in the series of results, just like __next__, but also provides a way for the caller to communicate with the generator, to affect its operation.

Technically, yield is now an expression form that returns the item passed to send, not a statement (though it can be called either way—as yield X, or A = (yield X)). The expression must be enclosed in parentheses unless it’s the only item on the right side of the assignment statement. For example, X = yield Y is OK, as is X = (yield Y) + 42.

When this extra protocol is used, values are sent into a generator G by calling G.send(value). The generator’s code is then resumed, and the yield expression in the generator returns the value passed to send. If the regular G.__next__() method (or its next(G) equivalent) is called to advance, the yield simply returns None. For example:

>>> def gen():

... for i in range(10):

... X = yield i

... print(X)

...

>>> G = gen()

>>> next(G) # Must call next() first, to start generator

0

>>> G.send(77) # Advance, and send value to yield expression

77

1

>>> G.send(88)

88

2

>>> next(G) # next() and X.__next__() send None

None

3

The send method can be used, for example, to code a generator that its caller can terminate by sending a termination code, or redirect by passing a new position. In addition, generators in 2.5 also support a throw(type) method to raise an exception inside the generator at the latest yield, and a close method that raises a special GeneratorExit exception inside the generator to terminate the iteration. These are advanced features that we won’t delve into in more detail here; see reference texts and Python’s standard manuals

Return Main Page Previous Page Next Page

®Online Book Reader