Python generators, what is a generator?


The generator is a special function, different from the general function, the general function call once, will always end and return; generator can be executed to a certain location to stop, through the yield to give up the execution right, the next time to call again, from the last yield after the place to start execution.

For example:

def generator():
    yield "a"
    yield "b"
    yield "c"

for i in generator():
    print(i);

python generator

Related course: Complete Python Programming Course & Exercises

How to create a python generator?

It's as simple as creating a function, except instead of using a return declaration, you use a yield declaration.

A function is a generator if it contains at least one yield declaration (of course it can also contain other yields or returns).

The difference is that a return declaration ends a function completely, whereas a yield declaration pauses the function, saves all its states, and continues to execute when called.

The difference between ### generator functions and normal functions

  • generator function contains more than one yield declaration

When the generator function is called, it returns an iterator object, but the function does not start executing immediately

  • __iter_() and __next_() methods are automatically implemented, so you can use the next() function to iterate over the returned iterator object

  • Once a generator is executed to the yield statement, the generator function is paused and the program control flow is transferred to the calling party

  • Between successive calls to the generator, the generator's local variables and state are saved

  • Eventually, the generator function is terminated and a call to the generator raises the StopIteration exception.

The following example illustrates all the above, we have a function called my_gen() with some yield statements.

# A simple generator function  
def my_gen():  
    n = 1  
    print('This is printed first')  
    # Generator function contains yield statements  
    yield n

    n += 1  
    print('This is printed second')  
    yield n

    n += 1  
    print('This is printed at last')  
    yield n

if __name__ == '__main__':
    a = my_gen()
    print a.next()
    print a.next()
    print a.next()

Interestingly, in this example the variable n is remembered between each call. Unlike normal functions, local variables are not destroyed after the function yield, and the generator object can only be iterated this way once. To repeat the process above, you need to create another generator object like a = my_gen() and iterate on it using the NEXT method.

We can also use the for loop directly with the generator object, because a for loop receives an iterator object and iterates over it using the next() function, stopping automatically when a StopIteration exception is encountered.

# A simple generator function  
def my_gen():  
    n = 1  
    print('This is printed first')  
    # Generator function contains yield statements  
    yield n

    n += 1  
    print('This is printed second')  
    yield n

    n += 1  
    print('This is printed at last')  
    yield n

for item in my_gen():  
    print(item)

Reverse an example string.

def rev_str(my_str):
    length = len(my_str)
    for i in range(length - 1, -1, -1):
        yield my_str[i]

for char in rev_str("hello")
    print char

Why use generator in python?

1. Easy to achieve

The implementation of GENERATOR is clear and concise compared to the ITERATOR class. The following is an exponential function of 2 implemented with an iterator

class PowTwo:
    def __init__(self,max = 0):
        self.max = max

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n > self.max:
            raise StopIteration  
        result = 2 ** self.n

The generator does this

def PowTwoGen(max = 0):
    n = 0
    while n < max:
        yield 2**n
        n += 1

Because GENERATOR automatically tracks implementation details, it's clearer and more concise.

2. Memory savings

When a function returns a sequence, it builds the sequence in memory and returns it. If this sequence contains a lot of data, it's too much.

And if the sequence is implemented as a generator, it is memory friendly because he only generates one ITEM at a time.

3. represents an unlimited stream

GENERATOR is a great tool for representing infinite data flows. Infinite streams cannot be stored in memory, and because the generator generates an item each time, it can represent an infinite stream.

The following code can produce all the odd numbers

def all_even():
    n = 1
    while True:
        yield n
        n += 2

4.generator pipeline (pipeline)

The generator can perform pipeline operations for a range of operations.

Let's say we have a journal of a fast food chain. The fourth column in the log is the number of pizzas sold per hour, and we wanted to sum this data for the last five years.

Assuming that all data are characters and unavailable data are represented by "N/A", using generator can be achieved like this

with open('sells.log') as file:
    pizza_col = (line[3] for line in file) 
    per_hour = (int(x) for x in pizza_col if x != 'N/A')
    print "Total pizzas sold = ",sum(per_hour)