Overview

itertools provides building blocks for lazy iteration. All functions return iterators, not lists; they compute values on demand and compose without intermediate allocations. This makes them efficient for large data streams and functional-style pipelines. Wrap in list() or tuple() when you need a concrete sequence. This card covers the most-used functions with concise examples.

Chaining and flattening

These functions concatenate or flatten iterables without building intermediate lists.

FunctionSignatureExampleOutput
chainchain(*iterables)chain([1,2],[3,4])1,2,3,4
chain.from_iterablechain.from_iterable(iterable)chain.from_iterable([[1,2],[3,4]])1,2,3,4
zip_longestzip_longest(*its, fillvalue=None)zip_longest([1,2],[3])(1,3),(2,None)
repeatrepeat(val, n)list(repeat(0, 3))[0,0,0]
cyclecycle(iterable)cycle([1,2,3])1,2,3,1,2,3,...
countcount(start, step)count(0, 5)0,5,10,15,...

Use chain.from_iterable instead of chain(*nested) when the number of sub-iterables is large; unpacking to *args has a stack limit.

Slicing iterators

FunctionSignatureExampleOutput
isliceislice(it, stop) or islice(it, start, stop, step)islice(range(100), 5, 15, 2)5,7,9,11,13
takewhiletakewhile(pred, it)takewhile(lambda x: x<5, [1,3,6,2])1,3
dropwhiledropwhile(pred, it)dropwhile(lambda x: x<5, [1,3,6,2])6,2
filterfalsefilterfalse(pred, it)filterfalse(str.isdigit, "a1b2")'a','b'
compresscompress(data, selectors)compress("ABCD",[1,0,1,0])'A','C'

islice does not support negative indices. To get the last n items from an iterator use collections.deque(it, maxlen=n).

Combinatorics

All combinatoric functions return tuples.

FunctionSignatureExampleOutput
combinationscombinations(it, r)combinations([1,2,3], 2)(1,2),(1,3),(2,3)
combinations_with_replacementcombinations_with_replacement(it, r)combinations_with_replacement([1,2], 2)(1,1),(1,2),(2,2)
permutationspermutations(it, r=None)permutations([1,2,3], 2)(1,2),(1,3),(2,1),(2,3),(3,1),(3,2)
productproduct(*its, repeat=1)product([0,1], repeat=2)(0,0),(0,1),(1,0),(1,1)

product is equivalent to nested for loops: product(A, B, C) = for a in A: for b in B: for c in C: yield (a,b,c).

Count of results:

  • combinations(n, r): n! / (r! * (n-r)!)
  • permutations(n, r): n! / (n-r)!
  • product(n, repeat=r): n ** r

groupby

groupby groups consecutive items in an iterable that have the same key. Sort first if you want all occurrences of a key together.

from itertools import groupby
 
data = sorted([
    {"dept": "eng", "name": "Alice"},
    {"dept": "eng", "name": "Bob"},
    {"dept": "hr",  "name": "Carol"},
], key=lambda x: x["dept"])
 
for dept, members in groupby(data, key=lambda x: x["dept"]):
    print(dept, list(members))
# eng [{'dept': 'eng', 'name': 'Alice'}, {'dept': 'eng', 'name': 'Bob'}]
# hr  [{'dept': 'hr', 'name': 'Carol'}]
PatternNotes
groupby(sorted_it, key=fn)Standard usage: sort by key first
groupby(it)Groups equal adjacent values; no key function
Consume the group iterator immediatelyThe group iterator becomes invalid once the outer iterator advances

The most common bug: iterating the outer groupby iterator a second time without consuming the group iterators first causes empty groups. {k: list(v) for k, v in groupby(...)} is the safe one-liner.

accumulate and reduce

accumulate is a running reduction; it yields each intermediate result.

FunctionSignatureExampleOutput
accumulateaccumulate(it, func=add, initial=None)accumulate([1,2,3,4])1,3,6,10
accumulate with maxaccumulate([3,1,4,1,5], max)running max3,3,4,4,5
accumulate with initialaccumulate([1,2,3], initial=10)10,11,13,16includes initial
functools.reducereduce(func, it, initial)reduce(mul, [1,2,3,4], 1)24 (final only)

Use accumulate when you need the running series; use functools.reduce when you only need the final value.

Common gotchas

  • All itertools functions return lazy iterators. Calling groupby(...) or chain(...) does no work until you iterate. Forgetting this leads to subtle bugs when the source data is mutated between creation and consumption.
  • groupby only groups adjacent equal keys. An unsorted input produces multiple groups for the same key. Always sort first.
  • The group iterator from groupby is invalidated when the outer iterator advances. Consume each group with list(group) before calling next() on the outer loop.
  • product(*[large_list] * 3) generates n**3 tuples. Check cardinality before materializing combinatoric results.
  • cycle loops forever. Always pair it with islice or takewhile or a zip to limit output.
  • count and repeat (without n) are infinite. They must be consumed with a terminating combinator.