Python Reduce Function: Should You Use It or Not?

Python’s reduce function is one of those topics you encounter the more you code in Python. It might sound complex, but is that really the case?

The Python reduce function applies a function of two arguments to the items of an iterable and it returns a single value. The function is applied to two items at a time from left to right until all the items of the iterable are processed. In other words, the function passed to reduce() is applied cumulatively to the iterable.

We will work with a few examples that use the reduce function to make sure you understand how to use it.

Let’s start coding!

How Does Reduce Work in Python?

In this section, we will go through an example of the Python reduce function.

The Python reduce() function is part of the functools module, this is a Python module that contains higher-order functions (act on or return other functions).

The functools.reduce() function takes a function and an iterable as arguments.

functools.reduce(functioniterable)

The reduce operation doesn’t return multiple values, it just returns a single value.

The reduce function reduces an iterable to a single value using a function (or any callable object) passed to it.

Here are the steps reduce follows to generate its result:

  1. It applies the function to the first two elements of the iterable and it generates a result.
  2. The function is then applied to the result of the previous step and to the next element in the iterable.
  3. The process continues until all the items in the iterable are processed.
  4. The final result is returned by the reduce function.

Let’s see how to reduce a list.

Write a function that adds two numbers:

def calculate_sum(x, y):
    return x + y

Then import the reduce function from the functools module, apply the function to a list of numbers, and print the result.

We are applying a function that takes two arguments to the reduce() function.

from functools import reduce

def calculate_sum(x, y):
    return x + y

numbers = [1, 3, 5, 7]
result = reduce(calculate_sum, numbers)
print("The result is {}".format(result))

Note: by using from … import we only import the reduce function from functools instead of importing the entire functools module.

When you execute this code you get the following result (here we are using Python 3):

$ python reduce.py
The result is 16

We have calculated the sum of all the elements of the list using reduce() that goes through the list from left to right.

To make sure it’s clear how reduce behaves below you can see how to compute the sum.

(((1 + 3) + 5) + 7) => 16

Can You Apply Python reduce Function to a Tuple?

Let’s replace the list we have used in the previous example with a tuple.

from functools import reduce

def calculate_sum(x, y):
    return x + y

numbers = (1, 3, 5, 7)
print(type(numbers))
result = reduce(calculate_sum, numbers)
print("The result is {}".format(result))

The output is correct:

<class 'tuple'>
The result is 16

The reduce function in Python can be applied to a tuple because the tuple is an iterable.

If you remember the definition we have given about the reduce() function at the beginning of this tutorial, the reduce() function is used with iterables.

Using the reduce() Function to Calculate the Product of the Elements in a List?

Let’s see if we can calculate the multiplication of the numbers in a list in a similar way to what we have done with the sum.

Write a function that takes two numbers and returns their product.

def multiply(x, y):
    return x * y

Then pass this function and the list used in the previous example to the reduce() function.

from functools import reduce

def multiply(x, y):
    return x * y

numbers = [1, 3, 5, 7]
result = reduce(multiply, numbers)
print("The result is {}".format(result))

Run the program and confirm that the output is correct:

The result is 105

You should see the output above that confirm that multiplication also works well with reduce().

How Can You Use Reduce With a Lambda?

In the previous section, we defined a function used to calculate the sum of two numbers. Then we passed that function to the reduce function.

A lambda function is also a valid argument for reduce(). We can replace the calculate_sum function with a lambda function.

lambda x, y : x + y

If we pass two numbers to this lambda in the Python shell we get back their sum:

>>> (lambda x, y: x + y)(1, 2)
3 

And now let’s pass this lambda as the first parameter of the reduce function…

from functools import reduce 

numbers = [1, 3, 5, 7]
result = reduce(lambda x, y: x + y, numbers)
print("The result is {}".format(result)) 

The output returned by reduce is:

$ python reduce.py 
The result is 16

Exactly the same output we got back when using the custom calculate_sum function.

Applying Python Reduce to an Empty List

Let’s find out what result we get when we pass an empty list to the reduce function.

As the 1st argument, we will keep the lambda used in the previous section. The 2nd argument is an empty list.

result = reduce(lambda x, y: x + y, [])
print("The result is {}".format(result)) 

[output]
Traceback (most recent call last):
  File "reduce.py", line 3, in <module>
    result = reduce(lambda x, y: x + y, [])
TypeError: reduce() of empty sequence with no initial value 

We get back a TypeError exception that complains about the fact that the reduce() argument is an empty sequence and that, also, we haven’t passed an initial value to the reduce function.

What does it mean exactly?

If you look at the Python documentation for the reduce function you will see that this function also supports an optional third argument, an initializer.

functools.reduce(functioniterable[, initializer])

If present, the initializer is placed before the items of the iterable in the calculation and it’s used as the default value in case the iterable is empty.

Update the code to pass an initializer equal to 10.

result = reduce(lambda x, y: x + y, [], 10)
print("The result is {}".format(result))

[output]
The result is 10 

This time the reduce function does not raise a TypeError exception. Instead, it returns the value of the initializer.

Before continuing verify the output from the reduce function when the initializer is present and the list is not empty:

result = reduce(lambda x, y: x + y, [1, 2], 10) 

What do you get back? Is the result what you expected?

Why Are You Getting the Python Error “reduce” is Not Defined?

If you are running a program that calls the reduce() function without importing it from functools you will get the following NameError exception:

Traceback (most recent call last):
  File "reduce.py", line 7, in <module>
    result = reduce(sum, numbers)
NameError: name 'reduce' is not defined 

The fix is simple, just add an import statement at the top of your Python program as shown before:

from functools import reduce

Difference Between Map and Reduce

Another function often mentioned together with reduce is the map function.

The main difference between map and reduce is that map() is applied to every item of an iterable one at the time and it returns an iterator.

Let’s see what happens if we pass the lambda function defined before to the map function.

>>> result = map(lambda x, y: x + y, [1, 2])
>>> print(list(result))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: <lambda>() missing 1 required positional argument: 'y' 

The Python interpreter raises a TypeError because the map function passes only one value to the lambda function.

Update the lambda function by removing y and by returning x multiplied by 2:

>>> result = map(lambda x: 2*x, [1, 2])
>>> print(type(result))
<class 'map'> 
>>> print(list(result))
[2, 4] 

This time the map function works as expected. It takes the list and it multiplies all its items by 2.

Notice that we have used the list() function to convert the map object returned by the map function into a list.

Reduce vs Python For Loop

I wonder how we can use a Python for loop to write a program that returns the same result as the reduce function.

We set the value of the result to 0 and then add each item in the list to the result of the previous iteration.

numbers = [1, 3, 5, 7] 
result = 0

for number in numbers:
    result += number

print("The result is {}".format(result)) 

As you can see we need a few lines of code to do what reduce does in a single line.

Reduce vs Python List Comprehension

There is a conceptual difference between the reduce function and a list comprehension.

Reduce starts from a Python list and returns a single value while a list comprehension applied to a list returns another list.

But there are some scenarios in which you can use a list comprehension and the reduce function in a similar way, for example, to flatten a list of lists.

Given the following list of lists:

>>> numbers = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Let’s see how we can use reduce to flatten this list of lists.

>>> from functools import reduce
>>> result = reduce(lambda x, y: x + y, numbers)
>>> print(result)
[1, 2, 3, 4, 5, 6, 7, 8, 9] 

As you can see we have converted the list of lists into a simple list that contains all the numbers. In this example, the reduce() function is used to concatenate the three lists to each other.

Now let’s write some Pythonic code to do this with a list comprehension.

>>> [item for number_group in numbers for item in number_group]
[1, 2, 3, 4, 5, 6, 7, 8, 9] 

The result is the same.

At the same time, I feel that the list comprehension is less readable than the expression using reduce if you are not very familiar with list comprehensions.

Which approach do you prefer?

Reduce vs Itertools.accumulate

The itertools module implements a function called accumulate.

How does it compare to the reduce function?

Firstly its syntax is different:

itertools.accumulate(iterable[, func*initial=None])

It accepts an iterable as the first argument and an optional function as the second argument.

Let’s apply it to our original list of numbers to see what happens…

>>> from itertools import accumulate
>>> numbers = [1, 3, 5, 7]
>>> print(type(accumulate(numbers)))
<class 'itertools.accumulate'>
>>> print(list(accumulate(numbers)))
[1, 4, 9, 16] 

The accumulate function creates an iterator that returns accumulated sums.

So the behavior is different from the one of the reduce function that just returns a single value.

Is Python reduce() Like a Loop?

The Python reduce function allows applying an accumulation logic to the items of an iterable.

In other words, it has a behavior that you can also write using a Python loop.

If the function parameter of reduce() is too complex is often better to use a loop instead of reduce(). This will make your code longer but more readable.

Why Was the Reduce Function Removed From Python?

The reduce function is part of the standard library in Python 2. In other words, it is a built-in function. With Python 3 the reduce() function has been moved to the functools module.

In an article titled “The fate of reduce() in Python 3000“, the creator of Python Guido van Rossum explains the reason for removing the reduce function from the standard library.

It’s easy to use the reduce function when passing to it a simple function argument (e.g. the sum function we have used in this tutorial). But when the function is complex it gets harder to understand what the reduce function returns.

The use of reduce() makes code less readable and that’s why it’s often better to write the accumulation logic that reduce() provides using an explicit loop.

It’s important to make sure your code is as clear as possible and it doesn’t take a considerable effort to understand what you had in mind when you were writing it (think about other developers who have to understand it).

Conclusion

You have reached the end of this tutorial and by now you have all the knowledge you need to use the Python reduce function.

You know how to use it by passing a custom function or a lambda function to it. Once again, the reduce() function allows reducing iterables.

We have also looked at how reduce compares to map and how you can write code that implements a logic similar to reduce using a for loop or a list comprehension (only in some cases).

Bonus read: in this tutorial, we have briefly talked about list comprehension. Learn how to use list comprehensions to give you more options when creating your Python code.

Leave a Comment