What Is a Keyword Generator?
A generator is a special type of function that generates one value at a time. Think of it as a recoverable function. Calling this function will return a generator [Generator] that can be used to generate continuous x values. Simply put, during the execution of the function, the yield statement will return the value you need to the place where the generator was called, and then exit the function. When a generator function is called once, execution starts from where it was last interrupted, and all variable parameters in the generator are saved for the next use.
- A generator is also an iterator, but you can only iterate over it once [1]
- With list generators, we can directly create a list. However, due to memory limitations, the list size is definitely limited. Moreover, creating a list of 1 million elements not only takes up a lot of storage space. If we only need to access the first few elements, the space occupied by the vast majority of the latter elements will be wasted.
- Therefore, if the list elements can be deduced according to some algorithm, can we continuously infer the subsequent elements during the loop? This eliminates the need to create a complete list, which saves a lot of space. In Python, this mechanism of looping while computing is called a Generator.
- There are many ways to create a generator. The first method is very simple. Just change a list generator [] to () and create a generator:
>>> L = [x * x for x in range (10)] >>> L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> g = (x * x for x in range (10)) >>> g <generator object <genexpr> at 0x104feab40>
- The difference between creating L and g is only the outermost [] and (), L is a list, and g is a generator. We can print every element of the list directly, but how do we print every element of the generator?
- If you want to print them one by one, you can use the generator's next () method:
>>> g.next () 0 >>> g.next () 1 >>> g.next () 4 >>> g.next () 9 >>> g.next () 16 >>> g.next () 25 >>> g.next () 36 >>> g.next () 49 >>> g.next () 64 >>> g.next () 81 >>> g.next () Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
- As we said, the generator saves the algorithm. Each time next () is called, the value of the next element is calculated. Until the last element is calculated. When there are no more elements, a StopIteration error is thrown.
- Of course, the above continuous call to the next () method is too perverted. The correct way is to use a for loop.
- So, after we create a generator, we basically never call the next () method, but instead iterate through a for loop.
- The generator is very powerful. If the calculation algorithm is more complicated, when a for loop similar to the list generation method cannot be implemented, it can also be implemented by a function. For example, in the famous Fibonacci sequence, except for the first and second numbers, any number can be obtained by adding the first two numbers: 1, 1, 2, 3, 5, 8, 13 , 21, 34, ... The Fibonacci sequence cannot be written using list generation, but it is easy to print it out using functions.
- Looking closely, you can see that the fib function actually defines the calculation rules of the Fibonacci sequence. It can start from the first element and calculate any subsequent elements. This logic is actually very similar to a generator.
- In other words, the above function and generator are only one step away. To turn the fib function into a generator, just change print b to yield b:
def fib (max): n, a, b = 0, 0, 1 while n <max: yield b a, b = b, a + b n = n + 1
- This is another way to define a generator. If a function definition contains the yield keyword, the function is no longer a normal function, but a generator:
>>> fib (6) <generator object fib at 0x104feaaa0>
- Here, the hardest thing to understand is that the execution flow of generators and functions is different. Functions are executed sequentially, and return when they encounter a return statement or the last function statement. The function that becomes a generator is executed every time next () is called, and it returns when it encounters a yield statement. When it executes again, it resumes execution from the yield statement that was returned last time.