Movatterモバイル変換


[0]ホーム

URL:


— FREE Email Series —

🐍 Python Tricks 💌

Python Tricks Dictionary Merge

🔒 No spam. Unsubscribe any time.

Browse TopicsGuided Learning Paths
Basics Intermediate Advanced
aialgorithmsapibest-practicescareercommunitydatabasesdata-sciencedata-structuresdata-vizdevopsdjangodockereditorsflaskfront-endgamedevguimachine-learningnewsnumpyprojectspythonstdlibtestingtoolsweb-devweb-scraping

Table of Contents

Python's reduce(): From Functional to Pythonic Style

Python's reduce(): From Functional to Pythonic Style

byLeodanis Pozo RamosReading time estimate 41mintermediatebest-practicespython

Table of Contents

Remove ads

Python’sreduce() is a function that implements a mathematical technique calledfolding orreduction.reduce() is useful when you need to apply a function to an iterable and reduce it to a single cumulative value. Python’sreduce() is popular among developers with afunctional programming background, but Python has more to offer.

In this tutorial, you’ll cover howreduce() works and how to use it effectively. You’ll also cover some alternative Python tools that can be morePythonic, readable, and efficient thanreduce().

In this tutorial, you’ll learn:

  • How Python’sreduce() works
  • What the more common reductionuse cases are
  • How tosolve these use cases usingreduce()
  • Whatalternative Python tools are available to solve these same use cases

With this knowledge, you’ll be able to decide which tools to use when it comes to solving reduction or folding problems in Python.

For a better understanding of Python’sreduce(), it would be helpful to have some previous knowledge of how to work withPython iterables, especially how to loop over them using afor loop.

Free Download:Get a sample chapter from Python Tricks: The Book that shows you Python’s best practices with simple examples you can apply instantly to write more beautiful + Pythonic code.

Exploring Functional Programming in Python

Functional programming is a programming paradigm based on breaking down a problem into a set of individual functions. Ideally, every function only takes a set of input arguments and produces an output.

In functional programming, functions don’t have any internal state that affects the output that they produce for a given input. This means that anytime you call a function with the same set of input arguments, you’ll get the same result or output.

In a functional program, input data flows through a set offunctions. Each function operates on its input and produces some output. Functional programming tries to avoid mutable data types and state changes as much as possible. It works with the data that flow between functions.

Other core features of functional programming include the following:

  • The use ofrecursion rather than loops or other structures as a primary flow control structure
  • A focus onlists or arrays processing
  • A focus onwhat is to be computed rather than onhow to compute it
  • The use ofpure functions that avoidside effects
  • The use ofhigher-order functions

There are several important concepts in this list. Here’s a closer look to some of them:

  • Recursion is a technique in which functions call themselves, either directly or indirectly, in order to loop. It allows a program to loop over data structures that have unknown or unpredictable lengths.

  • Pure functions are functions that have no side effects at all. In other words, they’re functions that do not update or modify anyglobal variable, object, or data structure in the program. These functions produce an output that depends only on the input, which is closer to the concept of a mathematical function.

  • Higher-order functions are functions that operate on other functions by taking functions as arguments, returning functions, or both, as withPython decorators.

Since Python is a multi-paradigm programming language, it provides some tools that support a functional programming style:

Even though Pythonisn’t heavily influenced by functional programming languages, back in 1993 there was a clear demand for some of the functional programming features listed above.

In response, several functional tools were added to the language. According toGuido van Rossum, they were contributed by a community member:

Python acquiredlambda,reduce(),filter() andmap(), courtesy of (I believe) a Lisp hacker who missed them and submitted working patches. (Source)

Over the years, new features such aslist comprehensions,generator expressions, and built-in functions likesum(),min(),max(),all(), andany() were viewed asPythonic replacements formap(),filter(), andreduce(). Guidoplanned to removemap(),filter(),reduce(), and evenlambda from the language in Python 3.

Luckily, this removal didn’t take effect, mainly because the Python community didn’t want to let go of such popular features. They’re still around and still widely used among developers with a strong functional programming background.

In this tutorial, you’ll cover how to use Python’sreduce() to process iterables and reduce them to a single cumulative value without using afor loop. You’ll also learn about some Python tools that you can use in place ofreduce() to make your code more Pythonic, readable, and efficient.

Getting Started With Python’sreduce()

Python’sreduce() implements a mathematical technique commonly known asfolding orreduction. You’re doing a fold or reduction when you reduce a list of items to a single cumulative value. Python’sreduce() operates on anyiterable—not just lists—and performs the following steps:

  1. Apply a function (or callable) to the first two items in an iterable and generate a partial result.
  2. Use that partial result, together with the third item in the iterable, to generate another partial result.
  3. Repeat the process until the iterable is exhausted and then return a single cumulative value.

The idea behind Python’sreduce() is to take an existing function, apply it cumulatively to all the items in an iterable, and generate a single final value. In general, Python’sreduce() is handy for processing iterables without writing explicitfor loops. Sincereduce() is written in C, its internal loop can be faster than an explicit Pythonfor loop.

Python’sreduce() was originally a built-in function (and still is inPython 2.x), but it was moved tofunctools.reduce() inPython 3.0. This decision was based on some possible performance and readability issues.

Another reason for movingreduce() tofunctools was the introduction of built-in functions likesum(),any(),all(),max(),min(), andlen(), which provide more efficient, readable, and Pythonic ways of tackling common use cases forreduce(). You’ll learn how to use them in place ofreduce() later in the tutorial.

In Python 3.x, if you need to usereduce(), then you first have to import the function into yourcurrent scope using animport statement in one of the following ways:

  1. import functools and then usefully-qualified names likefunctools.reduce().
  2. from functools import reduce and then callreduce() directly.

According to thedocumentation forreduce(), the function has the following signature:

Python
functools.reduce(function,iterable[,initializer])

The Python documentation also states thatreduce() is roughly equivalent to the following Python function:

Python
defreduce(function,iterable,initializer=None):it=iter(iterable)ifinitializerisNone:value=next(it)else:value=initializerforelementinit:value=function(value,element)returnvalue

Like this Python function,reduce() works by applying a two-argument function to the items ofiterable in a loop from left to right, ultimately reducingiterable to a single cumulativevalue.

Python’sreduce() also accepts a third and optional argument calledinitializer that provides a seed value to the computation or reduction.

In the next two sections, you’ll take an in-depth look at how Python’sreduce() works and the meaning behind each of its arguments.

The Required Arguments:function anditerable

The first argument to Python’sreduce() is a two-argument function conveniently calledfunction. This function will be applied to the items in an iterable to cumulatively compute a final value.

Even though theofficial documentation refers to the first argument ofreduce() as “a function of two arguments,” you can pass any Python callable toreduce() as long as the callable accepts two arguments. Callable objects includeclasses, instances that implement aspecial method called__call__(),instance methods, class methods, static methods, and functions.

Note: For more details about Python callable objects, you can check out the Pythondocumentation and scroll down to “Callable types.”

The second required argument,iterable, will accept any Python iterable, as its name suggests. This includeslists, tuples,range objects, generators, iterators,sets,dictionary keys and values, and any other Python objects that you can iterate over.

Note: If you pass an iterator to Python’sreduce(), then the function will need to exhaust the iterator before you can get a final value. So, the iterator at hand won’t remainlazy.

To understand howreduce() works, you’re going to write a function that computes the sum of twonumbers andprints the equivalent math operation to the screen. Here’s the code:

Python
>>>defmy_add(a,b):...result=a+b...print(f"{a} +{b} ={result}")...returnresult

This function calculates the sum ofa andb, prints a message with the operation using anf-string, and returns the result of the computation. Here’s how it works:

Python
>>>my_add(5,5)5 + 5 = 1010

my_add() is a two-argument function, so you can pass it to Python’sreduce() along with an iterable to compute the cumulated sum of the items in the iterable. Check out the following code that uses a list of numbers:

Python
>>>fromfunctoolsimportreduce>>>numbers=[0,1,2,3,4]>>>reduce(my_add,numbers)0 + 1 = 11 + 2 = 33 + 3 = 66 + 4 = 1010

When you callreduce(), passingmy_add() andnumbers as arguments, you get an output that shows all the operations thatreduce() performs to come up with a final result of10. In this case, the operations are equivalent to((((0 + 1) + 2) + 3) + 4) = 10.

The call toreduce() in the above example appliesmy_add() to the first two items innumbers (0 and1) and gets1 as the result. Thenreduce() callsmy_add() using1 and the next item innumbers (which is2) as arguments, getting3 as the result. The process is repeated untilnumbers runs out of items andreduce() returns a final result of10.

The Optional Argument:initializer

The third argument to Python’sreduce(), calledinitializer, is optional. If you supply a value toinitializer, thenreduce() will feed it to the first call offunction as its first argument.

This means that the first call tofunction will use the value ofinitializer and the first item ofiterable to perform its first partial computation. After this,reduce() continues working with the subsequent items ofiterable.

Here’s an example in which you usemy_add() withinitializer set to100:

Python
>>>fromfunctoolsimportreduce>>>numbers=[0,1,2,3,4]>>>reduce(my_add,numbers,100)100 + 0 = 100100 + 1 = 101101 + 2 = 103103 + 3 = 106106 + 4 = 110110

Since you supply a value of100 toinitializer, Python’sreduce() uses that value in the first call as the first argument tomy_add(). Note that in the first iteration,my_add() uses100 and0, which is the first item ofnumbers, to perform the calculation100 + 0 = 100.

Another point to note is that, if you supply a value toinitializer, thenreduce() will perform one more iteration than it would without aninitializer.

If you’re planning to usereduce() to process iterables that may potentially be empty, then it’s good practice to provide a value toinitializer. Python’sreduce() will use this value as its default return value wheniterable is empty. If you don’t provide aninitializer value, thenreduce() will raise aTypeError. Take a look at the following example:

Python
>>>fromfunctoolsimportreduce>>># Using an initializer value>>>reduce(my_add,[],0)# Use 0 as return value0>>># Using no initializer value>>>reduce(my_add,[])# Raise a TypeError with an empty iterableTraceback (most recent call last):  File"<stdin>", line1, in<module>TypeError:reduce() of empty sequence with no initial value

If you callreduce() with an emptyiterable, then the function will return the value supplied toinitializer. If you don’t supply aninitializer, thenreduce() will raise aTypeError when processing empty iterables.

Note: To dive deeper into what the Python traceback is, check outUnderstanding the Python Traceback.

Now that you’re familiar with howreduce() works, you’re ready to learn how to apply it to some common programming problems.

Reducing Iterables With Python’sreduce()

So far, you’ve learned how Python’sreduce() works and how to use it to reduce iterables using auser-defined function. You also learned the meaning of each argument toreduce() and how they work.

In this section, you’ll look at some common use cases forreduce() and how to solve them using the function. You’ll also learn about some alternative Python tools that you can use in place ofreduce() to make your code more Pythonic, efficient, and readable.

Summing Numeric Values

The"Hello, World!" of Python’sreduce() is thesum use case. It involves calculating the cumulative sum of a list of numbers. Say you have a list of numbers like[1, 2, 3, 4]. Its sum will be1 + 2 + 3 + 4 = 10. Here’s a quick example of how to solve this problem using a Pythonfor loop:

Python
>>>numbers=[1,2,3,4]>>>total=0>>>fornuminnumbers:...total+=num...>>>total10

Thefor loop iterates over every value innumbers and accumulates them intotal. The final result is the sum of all the values, which in this example is10. Avariable used liketotal in this example is sometimes called anaccumulator.

This is arguably the most common use case for Python’sreduce(). To implement this operation withreduce(), you have several options. Some of them include usingreduce() with one of the following functions:

To use a user-defined function, you need to code a function that adds two numbers. Then you can use that function withreduce(). For this example, you can rewritemy_add() as follows:

Python
>>>defmy_add(a,b):...returna+b...>>>my_add(1,2)3

my_add() adds two numbers,a andb, and returns the result. Withmy_add() in place, you can usereduce() to calculate the sum of the values in a Python iterable. Here’s how:

Python
>>>fromfunctoolsimportreduce>>>numbers=[1,2,3,4]>>>reduce(my_add,numbers)10

The call toreduce() appliesmy_add() to the items innumbers to compute their cumulative sum. The final result is10, as expected.

You can also perform the same computation by using alambda function. In this case, you need alambda function that takes two numbers as arguments and returns their sum. Take a look at the following example:

Python
>>>fromfunctoolsimportreduce>>>numbers=[1,2,3,4]>>>reduce(lambdaa,b:a+b,numbers)10

Thelambda function takes two arguments and returns their sum.reduce() applies thelambda function in a loop to compute the cumulative sum of the items innumbers.

Likewise, you can take advantage of Python’soperator module. This module exports a bunch of functions that correspond to Python’s intrinsic operators. For the problem at hand, you can useoperator.add() along with Python’sreduce(). Check out the following example:

Python
>>>fromoperatorimportadd>>>fromfunctoolsimportreduce>>>add(1,2)3>>>numbers=[1,2,3,4]>>>reduce(add,numbers)10

In this example,add() takes two arguments and returns their sum. So, you can useadd() withreduce() to compute the sum of all the items ofnumbers. Sinceadd() is written in C and optimized for efficiency, it may be your best choice when usingreduce() for solving the sum use case. Note that the use ofoperator.add() is also more readable than using alambda function.

The sum use case is so common in programming that Python, sinceversion 2.3, has included a dedicated built-in function,sum(), to solve it .sum() is declared assum(iterable[, start]).

start is an optional argument tosum() and defaults to0. The function adds the value ofstart to the items ofiterable from left to right and returns the total. Take a look at the following example:

Python
>>>numbers=[1,2,3,4]>>>sum(numbers)10

Sincesum() is a built-in function, you don’t need to import anything. It’s always available for you. Usingsum() is the most Pythonic way of solving the sum use case. It’s clean, readable, and concise. It follows a core Python principle:

Simple is better than complex. (Source)

The addition ofsum() to the language was a big win in terms of readability and performance as compared to usingreduce() or afor loop.

Note: For more details on comparing the performance ofreduce() with the performance of other Python reduction tools, check out the sectionPerformance is Key.

If you’re dealing with the sum use case, then good practice recommends the use ofsum().

Multiplying Numeric Values

Theproduct use case of Python’sreduce() is quite similar to the sum use case, but this time the operation is multiplication. In other words, you need to calculate the product of all the values in an iterable.

For example, say you have the list[1, 2, 3, 4]. Its product will be1 * 2 * 3 * 4 = 24. You can calculate this using a Pythonfor loop. Check out the following example:

Python
>>>numbers=[1,2,3,4]>>>product=1>>>fornuminnumbers:...product*=num...>>>product24

The loop iterates over the items innumbers, multiplying each item by the result of the previous iteration. In this case, the starting value for the accumulatorproduct should be1 instead of0. Since any number multiplied by zero is zero, a starting value of0 will always make your product equal to0.

This computation is also a quite popular use case for Python’sreduce(). Again, you’ll cover three ways for solving the problem. You’ll usereduce() with:

  1. A user-defined function
  2. Alambda function
  3. A function calledoperator.mul()

For option 1, you’ll need to code a custom function that takes two arguments and returns their product. Then you’ll use this function withreduce() to calculate the product of the items in an iterable. Take a look at the following code:

Python
>>>fromfunctoolsimportreduce>>>defmy_prod(a,b):...returna*b...>>>my_prod(1,2)2>>>numbers=[1,2,3,4]>>>reduce(my_prod,numbers)24

The functionmy_prod() multiplies two numbers,a andb. The call toreduce() iterates over the items ofnumbers and computes their product by applyingmy_prod() to successive items. The final result is the product of all the items innumbers, which in this example is24.

If you prefer to use alambda function to solve this use case, then you need a function that takes two arguments and returns their product. Here’s an example:

Python
>>>fromfunctoolsimportreduce>>>numbers=[1,2,3,4]>>>reduce(lambdaa,b:a*b,numbers)24

The anonymous function does the magic by multiplying successive items whilereduce() iterates overnumbers. Again, the result is the product of all the items innumbers.

You can also useoperator.mul() to tackle the product use case.operator.mul() takes two numbers and returns the result of multiplying them. This is the right functionality for solving the problem at hand. Check out the following example:

Python
>>>fromoperatorimportmul>>>fromfunctoolsimportreduce>>>mul(2,2)4>>>numbers=[1,2,3,4]>>>reduce(mul,numbers)24

Sincemul() is highly optimized, your code will perform better if you use this function rather than a user-defined function or alambda function. Note that this solution is much more readable as well.

Finally, if you’re usingPython 3.8, then you have access to a more Pythonic and readable solution to this use case. Python 3.8 has added a new function calledprod(), which lives in thePythonmath module. This function is analogous tosum() but returns the product of astart value multiplied by aniterable of numbers.

In the case ofmath.prod(), the argumentstart is optional and defaults to1. Here’s how it works:

Python
>>>frommathimportprod>>>numbers=[1,2,3,4]>>>prod(numbers)24

This is also a big win in terms of readability and efficiency as compared to usingreduce(). So, if you’re usingPython 3.8 and product reduction is a common operation in your code, then you’ll be better served by usingmath.prod() rather than Python’sreduce().

Finding the Minimum and Maximum Value

The problem offinding the minimum and maximum value in an iterable is also a reduction problem that you can solve using Python’sreduce(). The idea is to compare the items in the iterable to find the minimum or the maximum value.

Say you have the list of numbers[3, 5, 2, 4, 7, 1]. In this list, the minimum value is1 and the maximum value is7. To find these values, you can use a Pythonfor loop. Check out the following code:

Python
>>>numbers=[3,5,2,4,7,1]>>># Minimum>>>min_value,*rest=numbers>>>fornuminrest:...ifnum<min_value:...min_value=num...>>>min_value1>>># Maximum>>>max_value,*rest=numbers>>>fornuminrest:...ifnum>max_value:...max_value=num...>>>max_value7

Both loops iterate over the items inrest and update the value ofmin_value ormax_value according to the result of successive comparisons. Note that initially,min_value andmax_value hold the number3, which is the first value innumbers. The variablerest holds the remaining values innumbers. In other words,rest = [5, 2, 4, 7, 1].

Note: In the above examples, you use the Pythoniterable unpacking operator (*) tounpack or expand the values innumbers into two variables. In the first case, the net effect is thatmin_value gets the first value innumbers, which is3, andrest collects the remaining values in a list.

Check out the details in the following examples:

Python
>>>numbers=[3,5,2,4,7,1]>>>min_value,*rest=numbers>>>min_value3>>>rest[5, 2, 4, 7, 1]>>>max_value,*rest=numbers>>>max_value3>>>rest[5, 2, 4, 7, 1]

The Python iterable unpacking operator (*) is useful when you need to unpack a sequence or iterable into several variables.

For a better understanding of unpacking operations in Python, you can check outPEP 3132 Extended Iterable Unpacking andPEP 448 Additional Unpacking Generalizations.

Now, think about how you can find the minimum and maximum value in an iterable using Python’sreduce(). Again, you can use a user-defined function or alambda function depending on your needs.

The following code implements a solution that uses two different user-defined functions. The first function will take two arguments,a andb, and return their minimum. The second function will use a similar process, but it’ll return the maximum value.

Here are the functions and how you can use them with Python’sreduce() to find the minimum and maximum value in an iterable:

Python
>>>fromfunctoolsimportreduce>>># Minimum>>>defmy_min_func(a,b):...returnaifa<belseb...>>># Maximum>>>defmy_max_func(a,b):...returnaifa>belseb...>>>numbers=[3,5,2,4,7,1]>>>reduce(my_min_func,numbers)1>>>reduce(my_max_func,numbers)7

When you runreduce() withmy_min_func() andmy_max_func(), you get the minimum and maximum value innumbers, respectively.reduce() iterates over the items ofnumbers, compares them in cumulative pairs, and finally returns the minimum or maximum value.

Note: To implementmy_min_func() andmy_max_func(), you used a Python conditional expression, or ternary operator, as areturn value. For a deeper dive into what conditional expression are and how they work, check outConditional Statements in Python (if/elif/else).

You can also use alambda function to solve the minimum and maximum problem. Take a look at the following examples:

Python
>>>fromfunctoolsimportreduce>>>numbers=[3,5,2,4,7,1]>>># Minimum>>>reduce(lambdaa,b:aifa<belseb,numbers)1>>># Maximum>>>reduce(lambdaa,b:aifa>belseb,numbers)7

This time, you use twolambda functions that find out ifa is either less than or greater thanb. In this case, Python’sreduce() applies thelambda function to each value innumbers, comparing it with the result of the previous computation. At the end of the process, you get the minimum or maximum value.

The minimum and maximum problem is so common in programming that Python has added built-in functions to perform these reductions. These functions are conveniently calledmin() andmax(), and you don’t need to import anything to be able to use them. Here’s how they work:

Python
>>>numbers=[3,5,2,4,7,1]>>>min(numbers)1>>>max(numbers)7

When you usemin() andmax() to find the minimum and maximum item in an iterable, your code is way more readable as compared to using Python’sreduce(). Additionally, sincemin() andmax() are highly-optimized C functions, you can also say that your code will be more efficient.

So, when it comes to solving this problem in Python, it’s best to usemin() andmax() rather thanreduce().

Checking if All Values Are True

Theall-true use case of Python’sreduce() involves finding out whether or not all the items in an iterable are true. To solve this problem, you can usereduce() along with a user-defined function or alambda function.

You’ll start by coding afor loop to find out if all the items in an iterable are true. Here’s the code:

Python
>>>defcheck_all_true(iterable):...foriteminiterable:...ifnotitem:...returnFalse...returnTrue...>>>check_all_true([1,1,1,1,1])True>>>check_all_true([1,1,1,1,0])False>>>check_all_true([])True

If all of the values initerable are true, thencheck_all_true() returnsTrue. Otherwise, it returnsFalse. It also returnsTrue with empty iterables.check_all_true() implements ashort-circuit evaluation. This means that the function returns as soon as it finds a false value without processing the rest of the items initerable.

To solve this problem using Python’sreduce(), you’ll need to write a function that takes two arguments and returnsTrue if both arguments are true. If one or both arguments are false, then the function will returnFalse. Here’s the code:

Python
>>>defboth_true(a,b):...returnbool(aandb)...>>>both_true(1,1)True>>>both_true(1,0)False>>>both_true(0,0)False

This function takes two arguments,a andb. Then you use theand operator to test if both arguments are true. The return value will beTrue if both arguments are true. Otherwise, it’ll beFalse.

In Python, the following objects areconsidered false:

Any other object will be considered true.

You need to usebool() to convert the return value ofand into eitherTrue orFalse. If you don’t usebool(), then your function won’t behave as expected becauseand returns one of the objects in the expression instead ofTrue orFalse. Check out the following examples:

Python
>>>a=0>>>b=1>>>aandb0>>>a=1>>>b=2>>>aandb2

and returns the first value in the expression if it’s false. Otherwise, it returns the last value in the expression regardless of its truth value. That’s why you need to usebool() in this case.bool() returns theBoolean value (True orFalse) resulting from evaluating a Boolean expression or an object. Check out the examples usingbool():

Python
>>>a=0>>>b=1>>>bool(aandb)False>>>a=1>>>b=2>>>bool(aandb)True

bool() will always return eitherTrue orFalse after evaluating the expression or object at hand.

Note: To better understand Python operators and expressions, you can check outOperators and Expressions in Python.

You can passboth_true() toreduce() to check if all the items of an iterable are true or not. Here’s how this works:

Python
>>>fromfunctoolsimportreduce>>>reduce(both_true,[1,1,1,1,1])True>>>reduce(both_true,[1,1,1,1,0])False>>>reduce(both_true,[],True)True

If you passboth_true() as an argument toreduce(), then you’ll getTrue if all of the items in the iterable are true. Otherwise, you’ll getFalse.

In the third example, you passTrue to theinitializer ofreduce() to get the same behavior ascheck_all_true() and to avoid aTypeError.

You can also use alambda function to solve the all-true use case ofreduce(). Here are some examples:

Python
>>>fromfunctoolsimportreduce>>>reduce(lambdaa,b:bool(aandb),[0,0,1,0,0])False>>>reduce(lambdaa,b:bool(aandb),[1,1,1,2,1])True>>>reduce(lambdaa,b:bool(aandb),[],True)True

Thislambda function is quite similar toboth_true() and uses the same expression as a return value. It returnsTrue if both arguments are true. Otherwise, it returnsFalse.

Note that unlikecheck_all_true(), when you usereduce() to solve the all-true use case, there’s no short-circuit evaluation becausereduce() doesn’t return until it traverses the entire iterable. This can add extra processing time to your code.

For example, say you have the listlst = [1, 0, 2, 0, 0, 1] and you need to check if all the items inlst are true. In this case,check_all_true() will finish as soon as its loop processes the first pair of items (1 and0) because0 is false. You don’t need to continue iterating because you already have an answer for the problem at hand.

On the other hand, thereduce() solution won’t finish until it processes all the items inlst. That’s five iterations later. Now imagine what this would do to the performance of your code if you were processing a large iterable!

Fortunately, Python provides the right tool for solving the all-true problem in a Pythonic, readable, and efficient way: the built-in functionall().

You can useall(iterable) to check if all of the items initerable are true. Here’s howall() works:

Python
>>>all([1,1,1,1,1])True>>>all([1,1,1,0,1])False>>>all([])True

all() loops over the items in an iterable, checking the truth value of each of them. Ifall() finds a false item, then it returnsFalse. Otherwise, it returnsTrue. If you callall() with an empty iterable, then you getTrue because there’s no false item in an empty iterable.

all() is a C function that’s optimized for performance. This function is also implemented using short-circuit evaluation. So, if you’re dealing with the all-true problem in Python, then you should consider usingall() instead ofreduce().

Checking if Any Value Is True

Another common use case for Python’sreduce() is theany-true use case. This time, you need to find out if at least one item in an iterable is true. To solve this problem, you need to write a function that takes an iterable and returnsTrue if any item in the iterable is true andFalse otherwise. Take a look at the following implementation for this function:

Python
>>>defcheck_any_true(iterable):...foriteminiterable:...ifitem:...returnTrue...returnFalse...>>>check_any_true([0,0,0,1,0])True>>>check_any_true([0,0,0,0,0])False>>>check_any_true([])False

If at least one item initerable is true, thencheck_any_true() returnsTrue. It returnsFalse only ifall the items are false or if the iterable is empty. This function also implements a short-circuit evaluation because it returns as soon as it finds a true value, if any.

To solve this problem using Python’sreduce(), you need to code a function that takes two arguments and returnsTrue if at least one of them is true. If both are false, then the function should returnFalse.

Here’s a possible implementation for this function:

Python
>>>defany_true(a,b):...returnbool(aorb)...>>>any_true(1,0)True>>>any_true(0,1)True>>>any_true(0,0)False

any_true() returnsTrue if at least one of its arguments it true. If both arguments are false, thenany_true() returnsFalse. As withboth_true() in the above section,any_true() usesbool() to convert the result of the expressiona or b to eitherTrue orFalse.

ThePythonor operator works a little differently fromand. It returns the first true object or the last object in the expression. Check out the following examples:

Python
>>>a=1>>>b=2>>>aorb1>>>a=0>>>b=1>>>aorb1>>>a=0>>>b=[]>>>aorb[]

The Pythonor operator returns the first true object or, if both are false, the last object. So, you also need to usebool() to get a coherent return value fromany_true().

Once you have this function in place, you can continue with the reduction. Take a look at the following calls toreduce():

Python
>>>fromfunctoolsimportreduce>>>reduce(any_true,[0,0,0,1,0])True>>>reduce(any_true,[0,0,0,0,0])False>>>reduce(any_true,[],False)False

You’ve solved the problem using Python’sreduce(). Note that in the third example, you passFalse to the initializer ofreduce() to reproduce behavior of the originalcheck_any_true() and also to avoid aTypeError.

Note: Like the examples in the previous section, these examples ofreduce() don’t make a short-circuit evaluation. That means they can affect the performance of your code.

You can also use alambda function withreduce() to solve the any-true use case. Here’s how you can do it:

Python
>>>fromfunctoolsimportreduce>>>reduce(lambdaa,b:bool(aorb),[0,0,1,1,0])True>>>reduce(lambdaa,b:bool(aorb),[0,0,0,0,0])False>>>reduce(lambdaa,b:bool(aorb),[],False)False

Thislambda function is quite similar toany_true(). It returnsTrue if either of its two arguments is true. If both arguments are false, then it returnsFalse.

Even though this solution takes only one line of code, it can still make your code unreadable or at least difficult to understand. Again, Python provides a tool to efficiently solve the any-true problem without usingreduce(): the built-in functionany().

any(iterable) loops over the items initerable, testing the truth value of each until it finds a true item. The function returnsTrue as soon as it finds a true value. Ifany() doesn’t find a true value, then it returnsFalse. Here’s an example:

Python
>>>any([0,0,0,0,0])False>>>any([0,0,0,1,0])True>>>any([])False

Again, you don’t need to importany() to use it in your code.any() works as expected. It returnsFalse if all the items in the iterable are false. Otherwise, it returnsTrue. Note that if you callany() with an empty iterable, then you getFalse because there’s no true item in an empty iterable.

As withall(),any() is a C function optimized for performance. It’s also implemented using short-circuit evaluation. So, if you’re dealing with the any-true problem in Python, then consider usingany() instead ofreduce().

Comparingreduce() andaccumulate()

A Python function calledaccumulate() lives initertools and behaves similarly toreduce().accumulate(iterable[, func]) accepts one required argument,iterable, which can be any Python iterable. The optional second argument,func, needs to be a function (or a callable object) that takes two arguments and returns a single value.

accumulate() returns an iterator. Each item in this iterator will be the accumulated result of the computation thatfunc performs. The default computation is the sum. If you don’t supply a function toaccumulate(), then each item in the resulting iterator will be the accumulated sum of the previous items initerable plus the item at hand.

Check out the following examples:

Python
>>>fromitertoolsimportaccumulate>>>fromoperatorimportadd>>>fromfunctoolsimportreduce>>>numbers=[1,2,3,4]>>>list(accumulate(numbers))[1, 3, 6, 10]>>>reduce(add,numbers)10

Note that the last value in the resulting iterator is the same value thatreduce() returns. This is the main similarity between these two functions.

Note: Sinceaccumulate() returns an iterator, you need to calllist() to consume the iterator and get a list object as an output.

If, on the other hand, you supply a two-argument function (or callable) to thefunc argument ofaccumulate(), then the items in the resulting iterator will be the accumulated result of the computation performed byfunc. Here’s an example that usesoperator.mul():

Python
>>>fromitertoolsimportaccumulate>>>fromoperatorimportmul>>>fromfunctoolsimportreduce>>>numbers=[1,2,3,4]>>>list(accumulate(numbers,mul))[1, 2, 6, 24]>>>reduce(mul,numbers)24

In this example, you can again see that the last item in the returned value ofaccumulate() is equal to the value returned byreduce().

Considering Performance and Readability

Python’sreduce() can have remarkably bad performance because it works by calling functions multiple times. This can make your code slow and inefficient. Usingreduce() can also compromise the readability of your code when you use it with complex user-defined functions orlambda functions.

Throughout this tutorial, you’ve learned that Python offers a bunch of tools that can gracefully replacereduce(), at least for its main use cases. Here are the main takeaways of your reading up to this point:

  1. Use a dedicated function to solve use cases for Python’sreduce() whenever possible. Functions such assum(),all(),any(),max(),min(),len(),math.prod(), and so on will make your code faster and more readable, maintainable, andPythonic.

  2. Avoid complex user-defined functions when usingreduce(). These kinds of functions can make your code difficult to read and understand. You can use an explicit and readablefor loop instead.

  3. Avoid complexlambda functions when usingreduce(). They can also make your code unreadable and confusing.

The second and third points were concerns for Guido himself when he said the following:

So nowreduce(). This is actually the one I’ve always hated most, because, apart from a few examples involving+ or*, almost every time I see areduce() call with a non-trivial function argument, I need to grab pen and paper to diagram what’s actually being fed into that function before I understand what thereduce() is supposed to do. So in my mind, the applicability ofreduce() is pretty much limited to associative operators, and in all other cases it’s better to write out the accumulation loop explicitly. (Source)

The next two sections will help you implement this general advice in your code. They also provide some extra advice that will help you use Python’sreduce() effectively when you really need to use it.

Performance Is Key

If you’re going to usereduce() to solve the use cases that you’ve covered in this tutorial, then your code will be considerably slower as compared to code using dedicated built-in functions. In the following examples, you’ll usetimeit.timeit() to quickly measure the execution time of small bits of Python code and get an idea of their general performance.

timeit() takes several arguments, but for these examples, you’ll only need to use the following:

  • stmt holds the statement that you need to time.
  • setup takes additional statements for general setup, likeimport statements.
  • globals holds a dictionary containing theglobal namespace that you need to use for runningstmt.

Take a look at the following examples that time thesum use case usingreduce() with different tools and using Python’ssum() for comparison purposes:

Python
>>>fromfunctoolsimportreduce>>>fromtimeitimporttimeit>>># Using a user-defined function>>>defadd(a,b):...returna+b...>>>use_add="functools.reduce(add, range(100))">>>timeit(use_add,"import functools",globals={"add":add})13.443158069014316>>># Using a lambda expression>>>use_lambda="functools.reduce(lambda x, y: x + y, range(100))">>>timeit(use_lambda,"import functools")11.998800784000196>>># Using operator.add()>>>use_operator_add="functools.reduce(operator.add, range(100))">>>timeit(use_operator_add,"import functools, operator")5.183870767941698>>># Using sum()>>>timeit("sum(range(100))")1.1643308430211619

Even though you’ll get different numbers depending on your hardware, you’ll likely get the best time measurement usingsum(). This built-in function is also the most readable and Pythonic solution for the sum problem.

Note: For more a detailed approach to how to time your code, check outPython Timer Functions: Three Ways to Monitor Your Code.

Your second-best option would be to usereduce() withoperator.add(). The functions inoperator are written in C and are highly optimized for performance. So, they should perform better than a user-defined function, alambda function, or afor loop.

Readability Counts

Code readability is also an important concern when it comes to using Python’sreduce(). Even thoughreduce() will generally perform better than a Pythonfor loop, as Guido himself stated, a clean andPythonic loop is often easier to follow than usingreduce().

TheWhat’s New In Python 3.0 guide reinforces this idea when it says the following:

Usefunctools.reduce() if you really need it; however, 99 percent of the time an explicitfor loop is more readable. (Source)

To better understand the importance of readability, imagine that you’re starting to learn Python and you’re trying to solve an exercise about calculating the sum of all the even numbers in an iterable.

If you already know about Python’sreduce() and have done some functional programming in the past, then you might come up with the following solution:

Python
>>>fromfunctoolsimportreduce>>>defsum_even(it):...returnreduce(lambdax,y:x+yifnoty%2elsex,it,0)...>>>sum_even([1,2,3,4])6

In this function, you usereduce() to cumulatively sum the even numbers in an iterable. Thelambda function takes two arguments,x andy, and returns their sum if they’re even. Otherwise, it returnsx, which holds the result of the previous sum.

Additionally, you setinitializer to0 because otherwise your sum will have an initial value of1 (the first value initerable), which isn’t an even number and will introduce a bug into your function.

The function works as you expected, and you’re happy with the result. However, you continue digging into Python and learn aboutsum() andgenerator expressions. You decide to rework your function using these new tools, and your function now looks as follows:

Python
>>>defsum_even(iterable):...returnsum(numfornuminiterableifnotnum%2)...>>>sum_even([1,2,3,4])6

When you look at this code, you feel really proud, and you should. You’ve done a great job! That’s a beautiful Python function that almost reads as plain English. It’s also efficient and Pythonic. What do you think?

Conclusion

Python’sreduce() allows you to perform reduction operations on iterables using Python callables andlambda functions.reduce() applies a function to the items in an iterable and reduces them to a single cumulative value.

In this tutorial, you’ve learned:

  • Whatreduction, orfolding, is and when it might be useful
  • How to use Python’sreduce() to solve common reduction problems like summing or multiplying numbers
  • WhichPythonic tools you can use to effectively replacereduce() in your code

With this knowledge, you’ll be able to decide which tools best fit your coding needs when it comes to solving reduction problems in Python.

Over the years,reduce() has been replaced by more Pythonic tools likesum(),min(),max()all(),any(), among others. However,reduce() is still there and is still popular among functional programmers. If you have questions or thoughts about usingreduce() or any of its Python alternatives, then be sure to post them in the comments below.

🐍 Python Tricks 💌

Get a short & sweetPython Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

Python Tricks Dictionary Merge

AboutLeodanis Pozo Ramos

Leodanis is a self-taught Python developer, educator, and technical writer with over 10 years of experience.

» More about Leodanis

Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are:

MasterReal-World Python Skills With Unlimited Access to Real Python

Locked learning resources

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

Level Up Your Python Skills »

MasterReal-World Python Skills
With Unlimited Access to Real Python

Locked learning resources

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

Level Up Your Python Skills »

What Do You Think?

Rate this article:

What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.

Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students.Get tips for asking good questions andget answers to common questions in our support portal.


Looking for a real-time conversation? Visit theReal Python Community Chat or join the next“Office Hours” Live Q&A Session. Happy Pythoning!

Keep Learning

Related Topics:intermediatebest-practicespython

Related Learning Paths:

Related Tutorials:

Keep reading Real Python by creating a free account or signing in:

Already have an account?Sign-In

Almost there! Complete this form and click the button below to gain instant access:

Python Tricks: The Book

"Python Tricks: The Book" – Free Sample Chapter (PDF)

🔒 No spam. We take your privacy seriously.


[8]ページ先頭

©2009-2026 Movatter.jp