Generators and Lazy Sequences
A normal function builds a whole list in memory and hands it back. A generator produces values one at a time, only when asked. You write one by using yield instead of return.
def count_up_to(n):
i = 1
while i <= n:
yield i
i += 1
for value in count_up_to(3):
print(value) # 1, then 2, then 3Each time the loop asks for the next value, the function runs until the next yield, hands back that value, and pauses right there, remembering all its local state. The next request resumes from that line.
Why bother? Laziness. A generator can describe a huge or even endless sequence without ever holding it all at once:
def squares(numbers):
for n in numbers:
yield n * n
g = squares([1, 2, 3])
print(next(g)) # 1
print(next(g)) # 4
print(list(g)) # [9] (the rest)Anything that loops works on a generator: for, list(), sum(), max(). You can also write a quick one inline with a generator expression, which is like a list comprehension with parentheses:
total = sum(n * n for n in range(5)) # 0+1+4+9+16 = 30Rule of thumb: if you only need to iterate once and the data could be large, prefer a generator.
Write a generator function evens(n) that yields the even numbers from 0 up to but not including n, in order. So list(evens(7)) is [0, 2, 4, 6]. It must use yield (do not just build and return a list).
This lesson is locked
Lessons open one at a time. Finish the previous lesson to unlock this one.