Generators & yield
Generator functions use yield to produce a stream of values lazily. They preserve local state between steps - ideal for large files, infinite sequences, and ETL pipelines.
Search across all documentation pages
Generator functions use yield to produce a stream of values lazily. They preserve local state between steps - ideal for large files, infinite sequences, and ETL pipelines.
def squares(n: int):
for i in range(n):
yield i * i
for value in squares(5):
print(value)When to reach for this:
from pathlib import Path
def read_lines(path: Path):
with path.open(encoding="utf-8") as fh:
for line in fh:
yield line.rstrip("\n")
def filter_nonempty(lines):
for line in lines:
if line.strip():
yield line
def parse_csv_rows(lines):
for line in lines:
yield line.split(",")
def pipeline(path: Path):
lines = read_lines(path)
nonempty = filter_nonempty(lines)
return parse_csv_rows(nonempty)
if __name__ == "__main__":
sample = Path("data.csv")
sample.write_text("a,b\n\n c,d\n", encoding="utf-8")
for row in pipeline(sample):
print(row)What this demonstrates:
next()..gi_frame holds execution point (debugging).| Approach | Memory |
|---|---|
list(process()) | O(n) all items |
| generator pipeline | O(1) per stage state |
# generator expression
total = sum(x * x for x in range(1_000_000))
# close generator early
gen = squares(100)
next(gen)
gen.close() # raises GeneratorExit insidecontextlib.closing or try/finally in generator.gen.send(None) clarity in docs.| Alternative | Use When | Don't Use When |
|---|---|---|
| List comprehension | Small n, need reuse | Large streams |
itertools | Standard iterator ops | Custom domain logic per item |
| async generator | Async I/O streams | Sync file reads |
| pandas chunk iterator | Tabular batches | Simple line parsing |
Generator lazy single-pass. List stores all elements for reuse and indexing.
Delegates iteration to another iterable - flattens nested generators efficiently.
return value sets StopIteration.value (PEP 380) - consumed via yield from, rarely needed alone.
Coroutine-style communication into generator - advanced; asyncio uses similar ideas.
gen.close() triggers GeneratorExit at yield point - clean up resources in try/finally in gen.
Inject exception at yield point - testing and coroutine patterns.
Generator[YieldType, SendType, ReturnType] for advanced typing - often Iterator[T] enough.
Normal pattern - each yield produces one consumer step.
Generators save memory; list may be faster for tiny sequences due to overhead.
itertools.tee splits one iterator into two buffered iterators - memory cost grows.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026