All articles
3 min read

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.