Understanding functools.reduce in Python
functools.reduce applies a two-argument function cumulatively to reduce a sequence to a single value. Learn how it works, when to use it, and when to reach for simpler alternatives.
functools.reduce() takes a sequence and reduces it to a single value by repeatedly applying a two-argument function. It's the classic functional programming fold operation, and Python includes it in the functools module.
How It Works
from functools import reduce
reduce(function, iterable[, initializer])
reduce calls function(result, item) for each element in the iterable, where result starts as the first element (or the initializer if provided) and accumulates the return value of each call.
Visual breakdown for reduce(f, [a, b, c, d]):
f(a, b) → r1
f(r1, c) → r2
f(r2, d) → final result
Example: Factorial
from functools import reduce
def multiply(x, y):
return x * y
factorial_5 = reduce(multiply, range(1, 6))
print(factorial_5) # 120
With a lambda:
factorial_5 = reduce(lambda x, y: x * y, range(1, 6))
Example: Sum and Product
from functools import reduce
numbers = [1, 2, 3, 4, 5]
total = reduce(lambda a, b: a + b, numbers)
print(total) # 15
product = reduce(lambda a, b: a * b, numbers)
print(product) # 120
Example: Finding the Maximum
values = [3, 7, 2, 9, 4]
maximum = reduce(lambda a, b: a if a > b else b, values)
print(maximum) # 9
Example: Flattening a List
nested = [[1, 2], [3, 4], [5, 6]]
flat = reduce(lambda a, b: a + b, nested)
print(flat) # [1, 2, 3, 4, 5, 6]
Using the operator Module
For common operations, the operator module provides cleaner alternatives to lambdas:
from functools import reduce
from operator import mul, add
product = reduce(mul, [1, 2, 3, 4, 5]) # 120
total = reduce(add, [1, 2, 3, 4, 5]) # 15
The Initializer Argument
Provide a third argument to use as the starting value. This is important when the iterable might be empty:
# Without initializer — raises TypeError on empty list
reduce(lambda a, b: a + b, []) # TypeError
# With initializer — returns the initializer
reduce(lambda a, b: a + b, [], 0) # 0
The initializer also lets you start from a custom accumulator:
# Sum with a starting value of 100
result = reduce(lambda acc, x: acc + x, [1, 2, 3], 100)
print(result) # 106
When to Use reduce vs Alternatives
reduce is expressive but often less readable than a direct built-in. Before reaching for it, check if a simpler alternative exists:
| Operation | reduce version | Simpler alternative |
|---|---|---|
| Sum | reduce(add, nums) | sum(nums) |
| Product | reduce(mul, nums) | math.prod(nums) (3.8+) |
| Maximum | reduce(lambda a,b: a if a>b else b, nums) | max(nums) |
| Flatten one level | reduce(lambda a,b: a+b, nested) | itertools.chain.from_iterable(nested) |
Use reduce when there's no built-in that matches your operation — for example, merging a list of dicts, applying a pipeline of transformations, or building a tree structure from a list.
Conclusion
reduce is a powerful tool when the operation doesn't map to an existing built-in. For common aggregations like sum, product, or max, always prefer the dedicated built-in — it's faster and clearer. Reach for reduce when you're implementing something genuinely custom, and pair it with operator module functions to keep the code readable.