itertools and functools
Power tools for iteration.
Ava is planning gift bundles. She wants every pair of plants from her list, every possible order of three, and a running total of daily sales. Writing those loops by hand is error prone. The itertools module produces them in one line, and functools helps you reuse and speed up your functions.

- All pairs, and all orderings
- Running totals
- Smarter, faster functions
combinations and permutations
Combinations gives every group of a given size, where the order does not matter. Permutations gives every ordering, where it does. Product gives every pairing between two lists. Here Ava lists the possible bundles of two plants, and counts how many orders three plants can be arranged in.
from itertools import combinations, permutations, product
plants = ["fern", "ivy", "rose"]
print(list(combinations(plants, 2)))
print(len(list(permutations(plants, 3))))
print(list(product(["small", "large"], ["red", "blue"])))[('fern', 'ivy'), ('fern', 'rose'), ('ivy', 'rose')]
6
[('small', 'red'), ('small', 'blue'), ('large', 'red'), ('large', 'blue')]More itertools tools
Chain joins several lists into one stream. Accumulate gives running totals. Islice takes a slice of any iterable, even an endless one. Groupby groups neighbouring items. And zip longest pads shorter lists. These tools work lazily, producing items one at a time, so they use almost no memory.
from itertools import chain, accumulate, islice, count
print(list(chain([1, 2], [3], [4, 5])))
print(list(accumulate([24, 9, 14, 40])))
print(list(islice(count(10, 5), 4)))[1, 2, 3, 4, 5] [24, 33, 47, 87] [10, 15, 20, 25]
functools: reduce, partial, cache
Functools has three favourites. Reduce folds a list into one value. Partial fixes some arguments of a function, creating a new function. And cache remembers results, so repeated calls with the same input are instant. Here, a slow recursive Fibonacci becomes lightning fast with one line.
from functools import reduce, partial, cache
print(reduce(lambda a, b: a * b, [1, 2, 3, 4]))
vat = partial(round, ndigits=1)
print(vat(2.567))
@cache
def fib(n):
return n if n < 2 else fib(n - 1) + fib(n - 2)
print(fib(80))24 2.6 23416728348467685
Every pair of plants
Your turn. Using combinations, print every pair that you can make from four plants, and then print how many pairs there are. Ready? Here is one solution. Import combinations, turn the result into a list, and print it, with its length.
Print all 2-plant combinations of four plants and how many there are.
Show hint
list(combinations(items, 2))
Show solution
from itertools import combinations
plants = ["fern", "ivy", "rose", "aloe"]
pairs = list(combinations(plants, 2))
print(pairs)
print(len(pairs))[('fern', 'ivy'), ('fern', 'rose'), ('fern', 'aloe'), ('ivy', 'rose'), ('ivy', 'aloe'), ('rose', 'aloe')]
6Summary
Great job. Itertools builds combinations, permutations, running totals and streams, and functools gives you reduce, partial, and a powerful cache. Next, we go behind the scenes of loops, to understand iterators, and write generators that produce values on demand.
Key takeaways- combinations, permutations, product
- accumulate, chain, islice
- partial and @cache