1. What is a generator and how to create one?
In this lesson we'll answer the question: What is a generator and how to create one? Let's begin!
2. Definition
Generator is a special iterable object created by a function having a yield keyword in its body.
We're already familiar with functions that return something.
If we call them, the output will be the returned value.
3. Definition
In a generator function instead of return we have a yield keyword.
This keyword indicates that calling the function returns a generator object, not a value.
4. Generator as Iterable
Since a generator object is an Iterable,
we can use it in a for loop. We get the value that was beside our yield keyword. It looks weird though: to get just one value from an Iterable. But here is the trick.
5. More yields!
We can have as much yield keywords as we want! What does it mean?
It means that when we create our generator and insert it in a for loop,
we will sequentially get all the associated values.
6. Yield in a loop
Actually, we can define only one yield keyword within a loop, like in this example.
In this case, creating a generator and traversing through its items will give the following result. As can be seen, each call to the yield preserves the current state of the function until the next call.
7. Converting a generator to a list
Since generators are Iterables,
they can be passed to a list() constructor, which will result in a list of consecutive items retrieved from the generator.
8. Generator as Iterator
What else does it mean that a generator is an Iterable? Right! It has the associated Iterator!
And this Iterator is the generator itself!
If we define a generator
and retrieve it, we can use
the next() function
on it
until
the StopIteration error is raised. Thus, the sequence of yield keywords in the generator function indicates the sequence of values returned by the next() function applied to the Iterator.
9. Generators are expendable
The fact that generators are both an Iterable and an Iterator means that they are expendable. We can traverse through the generator items only once.
If we already used it in a loop, using it the second time will do nothing.
Therefore, we have to create it again.
10. Generators are expendable
The same is true if we use the list() constructor with a generator.
11. Generator comprehension
One more thing on generator creation.
Let's recall list comprehension.
Well, there is also a generator comprehension. The only difference is in using round brackets instead of square ones.
12. Traversal
Defining a generator using a generator comprehension does not change its behavior.
We still can use it in a for loop
or apply the next() function.
13. Why generators?
Generators seem to be quite complicated. Why do we actually need them?
First, it's a simple way to create a custom iterable object.
Assume we want to create such a list. How to do it programmatically can be quite puzzling
But here's the function to create the corresponding generator.
14. Why generators?
Secondly, generators have lazy initialization.
It means that we retrieve consecutive items when necessary and don't initialize the whole sequence first. It prevents the memory to be overloaded.
Assume we need to create such a sequence that is very long.
We can take the generator from the last example and retrieve each item separately without having to store anything more in memory.
15. Why generators?
The second point implies the third: the possibility to have infinite iterable objects.
Let's consider this generator. The while loop in its body does not break.
However, this generator is valid and can produce infinite amount of items without taking too much memory.
16. Let's practice!
That's it on generators! Let's get some practice!