Python itertools — Every Function Explained
itertools is Python’s standard library module for building iterator pipelines. Every function returns a lazy iterator — nothing is computed until you loop.
from itertools import *Infinite Iterators
count(start=0, step=1)
Counts forever from start, adding step each time.
for i in count(10, 2): # 10, 12, 14, 16 ...
if i > 20: breakcycle(iterable)
Repeats the iterable endlessly.
colors = cycle(["red", "green", "blue"])
next(colors) # red
next(colors) # green
next(colors) # blue
next(colors) # red ...repeat(object, times=None)
Yields object repeatedly, optionally times times.
list(repeat(42, 3)) # [42, 42, 42]Finite Iterators — Terminating on Shortest
accumulate(iterable, func=operator.add)
Yields running totals (or results of a binary function).
list(accumulate([1, 2, 3, 4])) # [1, 3, 6, 10]
list(accumulate([1, 2, 3, 4], mul)) # [1, 2, 6, 24]
list(accumulate([3, 1, 4, 1, 5], max)) # [3, 3, 4, 4, 5]chain(*iterables)
Concatenates iterables — like + for iterators.
list(chain([1, 2], [3, 4], [5])) # [1, 2, 3, 4, 5]chain.from_iterable(iterable_of_iterables)
Flatten one level.
list(chain.from_iterable([[1, 2], [3], [4, 5]])) # [1, 2, 3, 4, 5]compress(data, selectors)
Filters data where corresponding selectors element is truthy.
list(compress("ABCDEF", [1, 0, 1, 0, 1, 1])) # ['A', 'C', 'E', 'F']dropwhile(predicate, iterable)
Drops elements while predicate is true, then yields everything after.
list(dropwhile(lambda x: x < 5, [1, 4, 6, 3, 7]))
# [6, 3, 7] — stops checking after first Falsefilterfalse(predicate, iterable)
Like filter but keeps elements where predicate is false.
list(filterfalse(is_even, [1, 2, 3, 4])) # [1, 3]groupby(iterable, key=None)
Groups consecutive elements by key. The iterable must be sorted by the same key — groupby doesn’t sort for you.
items = [("a", 1), ("a", 2), ("b", 3), ("b", 4)]
for key, group in groupby(items, lambda x: x[0]):
print(key, list(group))
# a [(a,1), (a,2)]
# b [(b,3), (b,4)]islice(iterable, stop) / islice(iterable, start, stop, step=1)
Lazy slicing — like [start:stop:step] but on any iterable.
list(islice(range(100), 5)) # [0, 1, 2, 3, 4]
list(islice(range(100), 10, 20, 2)) # [10, 12, 14, 16, 18]pairwise(iterable)
Yields overlapping pairs (Python 3.10+).
list(pairwise("ABCD")) # [('A','B'), ('B','C'), ('C','D')]starmap(func, iterable_of_tuples)
Like map but unpacks each tuple as *args.
list(starmap(pow, [(2, 3), (3, 2), (5, 2)])) # [8, 9, 25]takewhile(predicate, iterable)
Yields elements while predicate is true, stops at first False.
list(takewhile(lambda x: x < 5, [1, 4, 6, 3, 7]))
# [1, 4]tee(iterable, n=2)
Creates n independent clones of an iterator. The original should not be used after tee.
it1, it2 = tee(range(3))
list(it1) # [0, 1, 2]
list(it2) # [0, 1, 2]zip_longest(*iterables, fillvalue=None)
Like zip but pads shorter iterables with fillvalue instead of stopping.
list(zip_longest("AB", "xyz", fillvalue="-"))
# [('A', 'x'), ('B', 'y'), ('-', 'z')]Combinatoric Iterators
product(*iterables, repeat=1)
Cartesian product — nested loops as an iterator.
list(product("AB", "12"))
# [('A','1'), ('A','2'), ('B','1'), ('B','2')]
list(product("AB", repeat=2))
# [('A','A'), ('A','B'), ('B','A'), ('B','B')]permutations(iterable, r=None)
All possible orderings of length r (defaults to full length).
list(permutations("ABC", 2))
# [('A','B'), ('A','C'), ('B','A'), ('B','C'), ('C','A'), ('C','B')]combinations(iterable, r)
All length-r combinations in lexicographic order (no repeats, order doesn’t matter).
list(combinations("ABC", 2))
# [('A','B'), ('A','C'), ('B','C')]combinations_with_replacement(iterable, r)
Like combinations but elements can repeat.
list(combinations_with_replacement("ABC", 2))
# [('A','A'), ('A','B'), ('A','C'), ('B','B'), ('B','C'), ('C','C')]Quick Reference Table
| Function | Input | Output | Lazy | Python |
|---|---|---|---|---|
count |
start, step | ∞ numbers | yes | 2.2+ |
cycle |
iterable | ∞ repeats | yes | 2.2+ |
repeat |
obj[, n] | n copies (∞ if no n) | yes | 2.2+ |
accumulate |
iterable[, func] | running totals | yes | 3.2+ |
chain |
*iters | concatenation | yes | 2.2+ |
chain.from_iterable |
iter of iters | flatten 1 level | yes | 2.6+ |
compress |
data, selectors | filtered by selector | yes | 3.1+ |
dropwhile |
pred, iterable | drops while True | yes | 2.2+ |
filterfalse |
pred, iterable | keeps where False | yes | 2.2+ |
groupby |
iterable[, key] | key, sub-iterators | yes | 2.2+ |
islice |
iter, [start,] stop[, step] | lazy slice | yes | 2.2+ |
pairwise |
iterable | overlapping pairs | yes | 3.10+ |
starmap |
func, pairs | func(*pair) | yes | 2.2+ |
takewhile |
pred, iterable | yields while True | yes | 2.2+ |
tee |
iterable, n | n independent clones | yes | 2.2+ |
zip_longest |
*iters[, fillvalue] | zip padded | yes | 2.6+ |
product |
*iters[, repeat] | cartesian product | yes | 2.6+ |
permutations |
iterable, r | r-length orderings | yes | 2.6+ |
combinations |
iterable, r | r-length combos | yes | 2.6+ |
combinations_with_replacement |
iterable, r | r-length combos w/ repeats | yes | 2.6+ |
Real-World Patterns
Chunking a list
def chunked(iterable, n):
it = iter(iterable)
return iter(lambda: list(islice(it, n)), [])
list(chunked(range(10), 3))
# [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]Partitioning by predicate
def partition(pred, iterable):
t1, t2 = tee(iterable)
return list(filterfalse(pred, t1)), list(filter(pred, t2))
evens, odds = partition(lambda x: x % 2 == 0, range(10))Nested loop flattening
matrix = [[1, 2], [3, 4], [5, 6]]
flat = list(chain.from_iterable(matrix)) # [1, 2, 3, 4, 5, 6]Unique elements in insertion order
def unique(iterable):
seen = set()
return (x for x in iterable if x not in seen and not seen.add(x))Sliding window
def sliding_window(iterable, n):
iters = tee(iterable, n)
for i, it in enumerate(iters):
next(islice(it, i, i), None)
return zip(*iters)
list(sliding_window("ABCDEF", 3))
# [('A','B','C'), ('B','C','D'), ('C','D','E'), ('D','E','F')]Golden rule: itertools functions compose beautifully. chain.from_iterable(map(func, data)), groupby(sorted(data), key), islice(cycle(colors), n) — build pipelines, not loops.