Python itertools Practice Guide: Lazy Streams
itertools is a toolbox for small iterator operations. The functions do not try to solve a whole problem; they compose. Once you recognize count, islice, chain, and groupby, many loops become shorter and easier to read.
Bound an infinite stream
count produces values forever. That is useful only when another function limits the request. islice takes a prefix without turning the whole stream into a list. The result is still lazy, so wrap it when you need to inspect it.
from itertools import count, islice
print(list(islice(count(10), 3)))A finite window
Join streams with chain
chain reads its inputs in order. It does not sort or deduplicate. That makes it a direct replacement for a loop that appends one list to another. If the inputs are large, chain avoids building the combined list up front.
from itertools import chain
print(list(chain([1, 2], ["a", "b"])))One stream from two
Group only adjacent keys
groupby emits a new group whenever the key changes. It does not search the entire input for matching keys. Sort by the same key before grouping when equal values are not adjacent. Consume each group before moving on.
from itertools import groupby
data = [("a", 1), ("a", 2), ("b", 3)]
for key, group in groupby(data, key=lambda pair: pair[0]):
print(key, list(group))Consecutive groups
Sort before grouping
The grouping key and the sort key must agree. A stable sort preserves the original order within equal keys, which is often what you want. After sorting, groupby can see all equal keys as one run.
from itertools import groupby
data = [("b", 1), ("a", 2), ("a", 3)]
sorted_data = sorted(data, key=lambda pair: pair[0])
print([(key, len(list(group))) for key, group in groupby(sorted_data, key=lambda pair: pair[0])])Sort, then group
Materialize deliberately
Most itertools results are iterators. They can be consumed once and do not support indexing. Convert to a list when you need to print, count, or traverse more than once. Do it at the boundary, not in the middle of every stage.
from itertools import chain
result = list(chain([1], [2, 3]))
print(result)
print(result[1])A list at the boundary
Your practice checklist
- Use islice to bound count or another infinite iterator.
- Use chain to join iterables without an append loop.
- Sort by the grouping key before groupby.
- Consume each group before advancing.
- Convert to a list only when you need indexing or reuse.
Common questions
Does groupby sort the data?
No. It groups adjacent items only. Sort by the same key first if equal keys may be separated.
Can chain combine strings?
Yes. It iterates each string character by character, just like a for loop over each string.
Why is my itertools result empty?
You probably consumed the iterator already. Iterators are single-use; create a new one or materialize a list.
Practice itertools
12 questions on count, islice, chain, groupby, and lazy iterator behavior.
Keep reading: