Reprint to: https://www.bytelang.com/article/content/NQbmUaRIXyA=
To create a iterator, you must implement a class with the __iter__ () and __next__ () methods that can track the internal state and throw a stopiteration exception when no element is returned.
The process is cumbersome and counterintuitive. Generator can solve this problem.
Python generator is a simple way to create a iterator. The tedious steps in front of you can be generator done automatically.
In simple terms, generator is a function that returns an Iterator object.
How do I create a python generator?
It's as simple as creating a function, but instead of using the return declaration, use the yield declaration.
If a function contains at least one yield declaration (which can also contain other yield or return), then it is a generator.
Yield and return will let the function return something, the difference is that the return declaration completely ends a function, and the yield declaration is a pause function, saving all its state, and subsequent calls will continue to execute.
The difference between generator function and ordinary function
- The generator function contains more than one yield declaration
- When the generator function is called, a iterator object is returned, but the function does not immediately begin execution
- The __iter__ () and __next__ () methods are automatically implemented, so you can use the next () function to iterate over this iterator object that is returned
- Once a generator executes to the yield statement, the generator function pauses and the program flow is transferred to the caller
- Between successive calls to generator, the local variables and states of the generator are saved
- Finally, the generator function terminates, and the call to generator throws a Stopiteration exception
The following example shows all the above points, and we have a function called My_gen () with some yield declarations.
# 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
Online Example: https://www.bytelang.com/o/s/c/nDeJ2dm7FUo=
Interestingly, in this case, the variable n is remembered between each invocation. Unlike the general function, the local variable is not destroyed after the function yield, and the generator object can only be iterated once.
To repeat the above procedure, you need to create another generator object like a = My_gen (), and use the next method to iterate over it.
Attention
: We can use the for loop directly with the generator object.
This is because a for loop receives a iterator object and uses the next () function to iterate over it and automatically stops when it encounters an stopiteration exception.
# A Simple Generator functionDefMy_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 was printed at last ') Yield n # Using for Loop # Output: # This is printed first # 1 # the is printed second # 2 # this was printed at last # 3 for item in My_gen (): Print (item)
Online Example: https://www.bytelang.com/o/s/c/3py5nUg_WVI=
Python generator with loops
The above example does not have practical application meaning, we just want to explore the principle behind.
In general, generator are implemented in conjunction with loops, and the loop has a termination condition.
Let's take a look at a reverse example of a string
def Rev_str (MY_STR): length = Len (my_str) for i in range (Length-1,-1, -1): yield My_str[i] # for loops to reverse the string # Output: # o # l # l Span class= "hljs-comment" ># e # H for char in rev_str (" hello "): print (char)
Online Example: https://www.bytelang.com/o/s/c/_rs3yQEbIhE=
We use the range () function inside the for loop to get the index in reverse order.
Generator can be applied to other types of iterator, such as list,tuple, in addition to string.
Python Generator expressions
Using generator expressions makes it easy to create simple generator.
Just as a lambda function can create an anonymous function, the generator function creates an anonymous generator function.
The syntax of the generator expression is similar to the Python list comprehension, except that the square brackets are replaced with parentheses.
The main difference between the list comprehension and generator expressions is that the former produces all of the list, which produces only one item at a time.
They are lazy and produce output only when they receive a request. Therefore, generator expressions are more memory-efficient than list comprehension.
# Initialize the list my_list = [1, 3, 6, 10] # square each term using list comprehension # Output: [1, 9, 36, 100] [x**2 for x in my_list] # same thing can be done using generator expression # Output: <generator object <genexpr> at 0x0000000002EBDAF8> (x**2 for x in my_list)
Online Example: https://www.bytelang.com/o/s/c/BgIb7R1NCls=
In the above example, the generator expression does not immediately produce the desired result, but instead returns a generator object when it is necessary to produce the item.
# Intialize the list my_list = [1, 3, 6, 10] a = (x**2 for x in my_list) # Output: 1 print(next(a)) # Output: 9 print(next(a)) # Output: 36 print(next(a)) # Output: 100 print(next(a)) # Output: StopIteration next(a)
Online Example: https://www.bytelang.com/o/s/c/p1^6fitxp5a=
Generator expressions can be used inside a function. Parentheses can be discarded when this is used.
Why use generator in Python? 1. Easy to achieve
The realization of generator is clear and concise relative to the iterator class. The following is a 2 exponential function implemented with iterator
class powtwo: def __init__ Self, max = 0): Self.max = max def __iter__0 return self def __ Next__if SELF.N > Self.max: raise stopiteration result = 2 * SELF.N SELF.N + = 1 return result
Generator This implementation
def PowTwoGen(max = 0): n = 0 while n < max: yield 2 ** n n += 1
Because generator automatically tracks implementation details, it is clearer and more concise.
2. Save Memory
When a function returns a sequence (sequence), the sequence is built in memory and returned. If the sequence contains a lot of data, it's too much.
And if the sequence is implemented in a generator way, it is memory-friendly because he produces only one item at a time.
3. Represents an infinite stream
Generator is a great tool for representing infinite streams of data. Unlimited data streams cannot be stored in memory, and because generator generates an item every time, it can represent an infinite stream of data.
The following code can produce all the odd
def all_even(): n = 0 while True: yield n n += 2
4.generator Pipeline (Pipeline)
Generator can perform pipelining operations on a range of operations.
Suppose we have a diary of a fast food chain. The fourth column in the log is the number of pizzas sold per hour, and we want to sum up this data for nearly 5 years.
Assuming all the data is characters, the unavailable data is denoted by "N/a" and can be implemented using generator
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))
This pipeline is both efficient and easy to read, and looks cool! :)
Generators tutorials in Python