Use generators for lazy pipelines¶
This guide shows common generator recipes. Use the Generators reference when you need exact syntax and typing rules.
Build a lazy filter¶
Use a generator function when the filtering logic benefits from names or multiple statements.
def non_empty(lines: List[str]) -> Generator[str]:
for line in lines:
cleaned = line.strip()
if cleaned != "":
yield cleaned
def main() -> None:
for line in non_empty(["", "alpha", " ", "beta"]):
println(line)
The loop consumes one yielded item at a time. The function does not allocate a list of every non-empty line first.
Transform and collect¶
Use iterator adapters such as map, filter, and take to keep the pipeline lazy until the final collect().
def square(n: int) -> int:
return n * n
def large(n: int) -> bool:
return n > 10
def main() -> None:
values = (n for n in [1, 2, 3, 4, 5]).map(square).filter(large).take(2).collect()
println(values[0])
println(values[1])
Use named functions for callbacks when the operation is shared or worth naming. Use a short closure when the logic is local and obvious.
Generators support the same adapter and consumer surface as other iterator values, including flat_map, skip, enumerate, zip, batch, count, fold, any, all, find, for_each, and sum.
Limit an unbounded producer¶
Pair an unbounded generator with take before collecting.
def count_up(start: int) -> Generator[int]:
mut current = start
while True:
yield current
current += 1
def main() -> None:
first_five = count_up(10).take(5).collect()
println(first_five[0])
println(first_five[4])
Do not call collect() on an unbounded generator unless an earlier helper limits it.
Return a generator from a helper¶
Return a generator when the caller should decide whether to loop, transform, limit, or collect.
def positive_scores(scores: List[int]) -> Generator[int]:
return (score for score in scores if score > 0)
def main() -> None:
top_two = positive_scores([3, -1, 5, 8]).take(2).collect()
println(top_two[0])
println(top_two[1])
This keeps the helper composable. A caller that only needs iteration can use for score in positive_scores(scores): without materializing a list.
Choose between lists and generators¶
Use a list comprehension when the next step needs random access, length, or repeated iteration over the full result. Use a generator when the next step can consume items once in order.
eager = [n * 2 for n in numbers]
lazy = (n * 2 for n in numbers)
The first expression builds a list now. The second expression builds a generator that produces doubled values later.