AI Hints
Home›Python Tutorial›Modern Classes and the Standard Library
Python · Lesson 21 of 49

itertools and functools

Power tools for iteration.

⏱ 2 min read▶ Video at 1:07:18🎓 Free
Watch this lesson in the Python courseWatch on YouTube ↗Full Python course

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.

itertools and functools
From the video: itertools and functools
  • 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.

iter1.pypython
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"])))
Output
[('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.

iter2.pypython
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)))
Output
[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.

functools1.pypython
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))
Output
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.

✍️ Exercise: Every pair of plants

Print all 2-plant combinations of four plants and how many there are.

Show hint

list(combinations(items, 2))

Show solution
pairs.pypython
from itertools import combinations

plants = ["fern", "ivy", "rose", "aloe"]
pairs = list(combinations(plants, 2))
print(pairs)
print(len(pairs))
Output
[('fern', 'ivy'), ('fern', 'rose'), ('fern', 'aloe'), ('ivy', 'rose'), ('ivy', 'aloe'), ('rose', 'aloe')]
6

Summary

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
Next up: Iterators and Generators — produce values only when needed