Generators is a powerful weapon of Python. Generators help you write concise code, give you lazy evaluation, and improve the efficience for calculating large sets of results. Personally I think it’s a good habit to use generators in Python whenever you can, if you really want your code to be Pythonic.
How to create a generator
There are mainly two ways to create a generator: using the yield
keyword in the function, or using the ()
as a generator expression.
- The
yield
keyword makes the function yields control back to the calling function on every iteration - The
()
expression returns a generator object
How to refactor a function to use a generator
Functions that construct a list or another iterable and returns it can be turned into a generator by:
- Converting the list append into a
yield
- Removing the empty list creation
- Removing the return
A generator example
Let’s see an example: implement a function that takes a list and return a list of the current running mean. For example, given the input list [8, 4, 3, 1, 3, 5]
, the expected return result is [8.0, 6.0, 5.0, 4.0, 3.8, 4.0]
.
First we’ll implement it without using generators.
1 2 3 4 5 6 7 8 9 10 |
|
Now we can refactor the above implementation to use a generator:
1 2 3 4 5 6 7 8 |
|
What we did in the refactoring was: replacing the list appending with a yield (average.append()
), removing the empty list creation (average = []
), and replacing the return statement with a yield statement.
One important property of Python generator object is it is a single-use object. In other words, a generator keeps yielding answers forever. The looping in a generator only ends when the calling function decides to end it. Meanwhile a generator can only be called once.
A few other generator examples can be found on my GitHub repo IntermediatePython