Easy Tutorial
❮ Deconstruction Assignment Android Tutorial Relativelayout ❯

A Brief Analysis of the Use of Python's yield

Category Programming Techniques

You may have heard that a function with yield in Python is called a generator. What is a generator?

Let's put aside the concept of a generator for now and use a common programming problem to illustrate the concept of yield.


How to Generate the Fibonacci Sequence

The Fibonacci sequence is a very simple recursive sequence. Except for the first and second numbers, any number can be obtained by adding the previous two numbers. Outputting the first N numbers of the Fibonacci sequence with a computer program is a very simple problem, and many beginners can easily write the following function:

Listing 1. Simple Output of the First N Numbers of the Fibonacci Sequence

Example

#!/usr/bin/python
# -*- coding: UTF-8 -*-

def fab(max): 
    n, a, b = 0, 0, 1 
    while n < max: 
        print b 
        a, b = b, a + b 
        n = n + 1
fab(5)

Executing the above code, we get the following output:

1 
1 
2 
3 
5

The result is correct, but experienced developers will point out that directly printing numbers in the fab function will lead to poor reusability of the function, because the fab function returns None, and other functions cannot obtain the sequence generated by this function.

To improve the reusability of the fab function, it is best not to print the sequence directly, but to return a List. The following is the second version of the rewritten fab function:

Listing 2. Output the First N Numbers of the Fibonacci Sequence, Second Edition

Example

#!/usr/bin/python
# -*- coding: UTF-8 -*-

def fab(max): 
    n, a, b = 0, 0, 1 
    L = [] 
    while n < max: 
        L.append(b) 
        a, b = b, a + b 
        n = n + 1 
    return L

for n in fab(5): 
    print n

The List returned by the fab function can be printed in the following way:

1 
1 
2 
3 
5

The rewritten fab function meets the requirements of reusability by returning a List, but more experienced developers will point out that the memory occupied by this function will increase with the increase of the parameter max. If you want to control the memory occupation, it is best not to use a List to save intermediate results, but to iterate through an iterable object. For example, in Python2.x, the code:

Listing 3. Iteration through an iterable object

for i in range(1000): pass

will generate a List of 1000 elements, while the code:

for i in xrange(1000): pass

will not generate a List of 1000 elements, but will return the next value in each iteration, occupying very little memory space. Because xrange does not return a List, but returns an iterable object.

Using iterable, we can rewrite the fab function as a class that supports iterable, which is the third version of Fab:

Listing 4. Third Version

Example

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class Fab(object): 

    def __init__(self, max): 
        self.max = max 
        self.n, self.a, self.b = 0, 0, 1 

    def __iter__(self): 
        return self 

    def next(self): 
        if self.n < self.max: 
            r = self.b 
            self.a, self.b = self.b, self.a + self.b 
            self.n = self.n + 1 
            return r 
        raise StopIteration()

for n in Fab(5): 
    print n

The Fab class continuously returns the next number in the sequence through next(), and the memory occupation is always constant:

1 
1 
2 
3 
5

However, this version rewritten using class is far less concise than the first version of the fab function. If we want to maintain the conciseness of the first version of the fab function while also obtaining the effect of iterable, yield comes into play:

Listing 5. Fourth Edition Using yield

Example

```

!/usr/bin/python

-- coding: UTF-8 --

def fab(max): n, a, b = 0, 0, 1 while n < max: yield b # Using yield # print b

❮ Deconstruction Assignment Android Tutorial Relativelayout ❯