Analysis of Python yield usage

What does the Python keyword yield do? for what? Answer: In order to understand what a yield is, you must understand what a generator is. Before understanding generators, let's walk a little closer to iteration.

iterable object

When you build a list, you can read the list item by item, which is called an iterable:

>>> mylist = [1, 2, 3]
>>> for i in mylist :
...    print(i)
1
2
3

mylist is an iterable object. When you use a list comprehension to create a list, you create an iterable object:

>>> mylist = [x*x for x in range(3)]
>>> for i in mylist :
...    print(i)
0
1
4

All you can use the for .. in .. syntax is called an iterator: list, string, file... You use them a lot because you can read the elements as you want, but you put all the values are stored in memory, which is not what you want if you have a lot of data.

Builder

The generator is iterable, but you can only read it once because it doesn't keep all the values ​​in memory, it generates data in real time:

>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator :
...    print(i)
0
1
4

Seems to be no different except replacing [] with (). However, you cannot use for i in mygenerator again, because the generator can only be iterated once: 0 is calculated, then 1 is calculated, then 4 is calculated, one after another...

yield keyword

yield is a keyword similar to return, except that the function returns a generator.

>>> def createGenerator() :
...    mylist = range(3)
...    for i in mylist :
...        yield i*i
...
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
...     print(i)
0
1
4

Example: Fibonacci sequence

The Fibonacci sequence is a very simple recursive sequence. Except for the second one and the second one, any number can be obtained by adding the first two numbers.

Example 1: Elementary Writing

There is no problem with the result. Printing numbers directly with print 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 the function (without the return function)

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

 >>> fab(5) 
 1 
 1 
 2 
 3 
 5

Example 2: Primary writing with return function

This writing method makes up for the drawbacks of Example 1. If you hesitate to return, a list will take up a lot of memory. If you want to control memory usage, it is better not to use list. For example, the difference between range and xrange

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 
 ... 
 1 
 1 
 2 
 3 
 5

Example 3: Class method to write iterator

Change the method to use __iter__ and next to achieve the method of generating the iterator, but the writing method is too complicated

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 
 ... 
 1 
 1 
 2 
 3 
 5

Example 4: yield version

Compared with the first version, just change the print to yield. Every time it executes to yield, it returns a generator. The next time the loop is repeated, it starts to execute from the back of yield until it returns to yield again.

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

>>> for n in fab(5): 
 ...     print n 
 ... 
 1 
 1 
 2 
 3 
 5

Another example of yield:

def read_file(fpath): 
    BLOCK_SIZE = 1024 
    with open(fpath, 'rb') as f: 
        while True: 
            block = f.read(BLOCK_SIZE) 
            if block: 
                yield block 
            else: 
                return

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326501053&siteId=291194637