Python
NameError
reduce
Python errors
troubleshooting

NameError name 'reduce' is not defined in Python

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Python 3, reduce() was moved from a built-in function to functools.reduce. Calling reduce() without importing it raises NameError: name 'reduce' is not defined. The fix is from functools import reduce. In Python 2, reduce was a built-in and required no import, which is why code ported from Python 2 often hits this error. The function applies a two-argument function cumulatively to a sequence, reducing it to a single value.

The Fix

python
1# Python 3 — must import from functools
2from functools import reduce
3
4numbers = [1, 2, 3, 4, 5]
5total = reduce(lambda a, b: a + b, numbers)
6print(total)  # 15

In Python 2, this worked without any import:

python
# Python 2 — reduce was a built-in
total = reduce(lambda a, b: a + b, [1, 2, 3, 4, 5])

Why Python 3 Moved reduce

Guido van Rossum argued that reduce() is rarely needed and often less readable than a simple loop. Python 3 removed it from built-ins to encourage clearer alternatives like sum(), math.prod(), any(), all(), and explicit loops. It was not removed entirely — it still lives in functools for cases where it genuinely simplifies code.

How reduce Works

python
1from functools import reduce
2
3# reduce(function, iterable, initializer)
4# Applies function(accumulator, current) left-to-right
5
6# Sum
7reduce(lambda a, b: a + b, [1, 2, 3, 4])  # ((1+2)+3)+4 = 10
8
9# Product
10reduce(lambda a, b: a * b, [1, 2, 3, 4])  # ((1*2)*3)*4 = 24
11
12# Maximum
13reduce(lambda a, b: a if a > b else b, [3, 1, 4, 1, 5])  # 5
14
15# With initializer (starting value)
16reduce(lambda a, b: a + b, [1, 2, 3], 100)  # 106
17
18# Flatten nested lists
19nested = [[1, 2], [3, 4], [5, 6]]
20flat = reduce(lambda a, b: a + b, nested)  # [1, 2, 3, 4, 5, 6]

Better Alternatives to reduce

For most common operations, Python provides clearer built-in alternatives:

python
1from functools import reduce
2import math
3import operator
4
5numbers = [1, 2, 3, 4, 5]
6
7# Sum — use sum() instead of reduce
8reduce(lambda a, b: a + b, numbers)  # Works but verbose
9sum(numbers)                          # Preferred
10
11# Product — use math.prod() (Python 3.8+)
12reduce(lambda a, b: a * b, numbers)  # Works
13math.prod(numbers)                    # Preferred
14
15# Max/Min — use built-in max()/min()
16reduce(lambda a, b: a if a > b else b, numbers)  # Works
17max(numbers)                                       # Preferred
18
19# String concatenation — use str.join()
20words = ["hello", "world"]
21reduce(lambda a, b: a + " " + b, words)  # Works
22" ".join(words)                            # Preferred
23
24# Boolean checks — use any()/all()
25reduce(lambda a, b: a or b, [False, True, False])  # True
26any([False, True, False])                            # True
27
28# Using operator module for cleaner reduce calls
29reduce(operator.add, numbers)  # 15
30reduce(operator.mul, numbers)  # 120

When reduce Is Actually Useful

python
1from functools import reduce
2
3# Composing functions
4def compose(*funcs):
5    return reduce(lambda f, g: lambda x: f(g(x)), funcs)
6
7double = lambda x: x * 2
8increment = lambda x: x + 1
9square = lambda x: x ** 2
10
11transform = compose(square, increment, double)
12print(transform(3))  # square(increment(double(3))) = square(7) = 49
13
14# Deep dictionary access
15data = {"a": {"b": {"c": 42}}}
16result = reduce(lambda d, key: d[key], ["a", "b", "c"], data)
17print(result)  # 42
18
19# Building a dictionary from pairs
20pairs = [("a", 1), ("b", 2), ("c", 3)]
21result = reduce(lambda d, kv: {**d, kv[0]: kv[1]}, pairs, {})
22# Better: dict(pairs)

Python 2/3 Compatibility

python
1# Compatible with both Python 2 and 3
2try:
3    reduce
4except NameError:
5    from functools import reduce
6
7# Or use the six compatibility library
8from six.moves import reduce

Common Pitfalls

  • Forgetting the import in Python 3: This is the most common cause. Code that worked in Python 2 breaks in Python 3. Add from functools import reduce at the top of the file. Using a linter like flake8 catches undefined names before runtime.
  • Using reduce when a built-in exists: reduce(lambda a, b: a + b, lst) is slower and harder to read than sum(lst). Similarly, reduce(operator.mul, ...) is less clear than math.prod(...) (Python 3.8+). Always check if a built-in covers your use case first.
  • Missing the initializer for empty sequences: reduce(lambda a, b: a + b, []) raises TypeError: reduce() of empty iterable with no initial value. Always provide an initializer when the input might be empty: reduce(func, items, default_value).
  • Assuming left-to-right associativity matters everywhere: reduce always folds left-to-right. For operations like subtraction, this matters: reduce(lambda a, b: a - b, [10, 3, 2]) gives (10 - 3) - 2 = 5, not 10 - (3 - 2) = 9. For non-associative operations, verify the fold direction is what you intend.
  • Performance issues with string concatenation: reduce(lambda a, b: a + b, strings) creates a new string on each step, giving O(n^2) performance. Use "".join(strings) for O(n) concatenation. The same applies to list concatenation — use itertools.chain instead.

Summary

  • reduce moved to functools.reduce in Python 3 — import it to fix the NameError
  • Use sum(), math.prod(), max(), min(), any(), all(), and str.join() instead of reduce when possible
  • Provide an initializer argument when the input sequence might be empty
  • reduce remains useful for function composition, deep data access, and custom accumulation patterns
  • For Python 2/3 compatibility, use a try/except import or the six library

Course illustration
Course illustration

All Rights Reserved.