Python provides ways to make looping easier. With a generator, we specify what elements are looped over. Generators are reusable—they make code simpler.
There are two ways to specify a generator. With the yield
-keyword, we encapsulate a looping mechanism into a method. With an expression, we use the for
-keyword to specify simpler generators.
The term yield has a meaning similar to "produce": it dispatches specified elements. Unlike return, control returns again to the method.
odds()
method yields odd elements in an iterable
. It has a yield statement in it.def odds(arg): # Yield odd elements in the iterable. for a in arg: if a % 2 != 0: yield a # An input list. items = [100, 101, 102, 103, 104, 105] # Display all odd items. for item in odds(items): print(item) # Print copied list. copy = list(odds(items)) print(copy)101 103 105 [101, 103, 105]
Sometimes in Python programs we see generator expressions. These return an iterator. Here we multiply each element in the list by 2 with a generator expression.
# Example integers. items = [100, 10, 1] # Use generator expression. multiplied = list(x * 2 for x in items) print(multiplied)[200, 20, 2]
In Python, list comprehensions are similar to generators. Are generators faster? In the Python documentation, we learn that list comprehensions tend to use more memory.
import time data = [1, 2, 3, 4, 5, 6, 7, 8, 9] print(time.time()) # Version 1: generator. i = 0 while i < 1000000: double = list(x * 2 for x in data) i += 1 print(time.time()) # Version 2: list comprehension. i = 0 while i < 1000000: double = [x * 2 for x in data] i += 1 print(time.time())1404138028.766 1404138031.806 Generator: 3.04 s [Python 3.3] 1404138033.569 List comprehension: 1.76 s 1404137810.806 1404137811.086 Generator: 0.28 s [PyPy 2.3.1] 1404137811.287 List comprehension: 0.20 s
In declarative programming (like generators), we specify our requirement with a declaration. Python then does the low-level work to fulfill our request.
map()
, we also create iterators in a declarative way.Generators simplify iteration. With them, we create looping abstractions. We then can reuse looping methods throughout programs—this leads to less code and higher-quality logic.