Functions · Lesson 12 of 18 · 18 min
Generators
yield, lazy pipelines, and itertools.
- Write generator functions with yield
- Build lazy pipelines
- Know when to materialize
yield pauses the function
A function with `yield` does not run its body on call. It returns a generator object. Each `next(gen)` (or each step of a for-loop) runs until the next `yield`, hands the value out, and freezes local state. When the function returns, the generator raises `StopIteration`.
This is how you stream data you cannot or should not hold in memory: file lines, network records, infinite sequences. `yield from subgen` delegates to another iterable.
def countdown(n):
while n > 0:
yield n
n -= 1
print(list(countdown(4)))
def squares(xs):
for x in xs:
yield x * x
def evens(xs):
for x in xs:
if x % 2 == 0:
yield x
print(list(evens(squares(range(8)))))itertools is the rest of the language
`itertools` is the standard library for lazy iteration: `islice`, `chain`, `cycle`, `repeat`, `count`, `groupby`, `product`, `permutations`, `combinations`. Combine them instead of writing index-heavy loops.
`yield` can also receive values with `gen.send(x)`, which is the foundation of older coroutine style. Modern async uses `async def` / `await` instead; do not mix the two styles without a reason.
from itertools import islice, chain, count
print(list(islice(count(10), 5)))
print(list(chain("ab", [1, 2])))
def take(n, it):
yield from islice(it, n)
print(list(take(3, countdown(10))))Check yourself
Quiz
1.Calling a generator function returns:
2.`yield from xs` is closest to:
3.len(countdown(5)) will:
Practice
Exercise
Write a generator `count_from(start)` that yields start, start+1, start+2, ... forever. Write `take(n, it)` that yields the first n items of it.
Tutor
Ask a question about this lesson. Answers are generated on demand and capped so the session stays focused.