You want the rolling maximum over a list of per-minute event counts — window size 3, one step at a time. For [1, 3, 2, 5, 4] that's [3, 3, 5]. How do you generate those lazily — one window at a time — instead of building the whole list up front?
A generator function? I've seen yield but never used it. Something that produces values as the caller pulls them?
Exactly. Replace return with yield and your function becomes a generator. Each call to next(gen) runs until the next yield, then pauses:
def window_max(values, size):
for i in range(len(values) - size + 1):
yield max(values[i:i+size])No list built in memory. One window max at a time.
And if I want the results as a list, I wrap the generator in list(...)?
Right. list(window_max(values, 3)) drains the generator and collects every yielded value. For small inputs that's fine — for ten million values, you iterate with for x in window_max(...) and never materialise the whole output.
What's the len(values) - size + 1 about? Off-by-one territory?
Number of windows. If you have 6 values and window size 3, the valid start indices are 0, 1, 2, 3 — that's 4 windows, which is 6 - 3 + 1. The +1 compensates for range being exclusive on the upper bound:
for i in range(len(values) - size + 1):
yield max(values[i:i+size])So generators turn any "produce a stream of results" problem into a few lines. Same pattern would work for rolling sum, rolling mean, or any aggregation.
Swap max for sum or statistics.mean and you have rolling averages. The generator structure is reusable; the aggregation is the variable part.
yieldTL;DR: yield turns a function into a lazy producer — values flow one at a time.
yield x — emit a value and pausefor v in gen — iterate lazilylist(gen) — drain into a listreturn value — the iterator ends when the function body exits| Situation | Use |
|---|---|
| tiny data | list comprehension |
| streaming / huge | generator |
| caller only needs one result | generator |
Generators are single-use — once drained, re-call the function to iterate again.
You want the rolling maximum over a list of per-minute event counts — window size 3, one step at a time. For [1, 3, 2, 5, 4] that's [3, 3, 5]. How do you generate those lazily — one window at a time — instead of building the whole list up front?
A generator function? I've seen yield but never used it. Something that produces values as the caller pulls them?
Exactly. Replace return with yield and your function becomes a generator. Each call to next(gen) runs until the next yield, then pauses:
def window_max(values, size):
for i in range(len(values) - size + 1):
yield max(values[i:i+size])No list built in memory. One window max at a time.
And if I want the results as a list, I wrap the generator in list(...)?
Right. list(window_max(values, 3)) drains the generator and collects every yielded value. For small inputs that's fine — for ten million values, you iterate with for x in window_max(...) and never materialise the whole output.
What's the len(values) - size + 1 about? Off-by-one territory?
Number of windows. If you have 6 values and window size 3, the valid start indices are 0, 1, 2, 3 — that's 4 windows, which is 6 - 3 + 1. The +1 compensates for range being exclusive on the upper bound:
for i in range(len(values) - size + 1):
yield max(values[i:i+size])So generators turn any "produce a stream of results" problem into a few lines. Same pattern would work for rolling sum, rolling mean, or any aggregation.
Swap max for sum or statistics.mean and you have rolling averages. The generator structure is reusable; the aggregation is the variable part.
yieldTL;DR: yield turns a function into a lazy producer — values flow one at a time.
yield x — emit a value and pausefor v in gen — iterate lazilylist(gen) — drain into a listreturn value — the iterator ends when the function body exits| Situation | Use |
|---|---|
| tiny data | list comprehension |
| streaming / huge | generator |
| caller only needs one result | generator |
Generators are single-use — once drained, re-call the function to iterate again.
Write `sliding_window_max(values, size)` that returns a list of the max value of each sliding window of length `size`. Use a generator helper (`yield max(...)`) inside and drain it with `list(...)` before returning.
Tap each step for scaffolded hints.
No blank-editor panic.