Evaluation of functions is the fundamental technique of computation in functional programming, which is a programming paradigm. Functional programming is a kind of programming. You will learn about functional programming in Python by following along with this tutorial.
The use of functional programming techniques is often restricted to a very minor capacity in Python programmes. Yet, it is beneficial to have a working knowledge of it. While reading code created by other people, you will almost certainly come across it at some point, even if just sometimes. It’s even possible that you’ll encounter scenarios in which it would be beneficial to employ Python’s functional programming features in your very own code. The following topics will be covered in this guide:
-
What the
functional programming
paradigm entails -
What it means to say that
functions
are
first-class citizens
in Python -
How to define
anonymous functions
with the
lambda
keyword -
How to implement functional code using
map()
,
filter()
, and
reduce()
What Is Functional Programming?
A function is said to be pure if the value that it returns is determined purely by the values that are sent into it and if there are no other effects that can be seen. Evaluation of pure functions makes up the whole of a programme written using the functional programming paradigm. The computation is carried out via the use of composed or nested function calls, without any modifications being made to the state or any mutable data.
The functional paradigm is one of the most widely used programming paradigms because it has various benefits over other paradigms. Functional code
is:
-
High level:
You’re describing the result you want rather than explicitly specifying the steps required to get there. Single statements tend to be concise but pack a lot of punch. -
Transparent:
The behavior of a pure function depends only on its inputs and outputs, without intermediary values. That eliminates the possibility of side effects, which facilitates
debugging
. -
Parallelizable:
Routines that don’t cause side effects can more easily
run in parallel
with one another.
Functional programming is supported in many different programming languages to varying degrees. The functional paradigm is followed almost entirely by the code written in some languages. Haskell is an example of such a language. Python, on the other hand, does enable functional programming, but it also has elements that are characteristic of other programming paradigms.
It’s true that a comprehensive explanation of functional programming can be difficult to understand, but the purpose of this article isn’t to give you a strict definition of the term; rather, it’s to demonstrate some of the things that can be accomplished with functional programming in various contexts.
Python.
How Well Does Python Support Functional Programming?
It is helpful for the development of functional programming if a function in a particular programming language takes two arguments.
abilities:
- To take another function as an argument
- To return another function to its caller
Python is a good choice for use in any of these situations. You should already know that everything in a Python programme is an object since you’ve learnt that information earlier in this course. In Python, all of the objects have about the same stature, and functions are not an exception to this rule.
Inside the Python programming language, functions are treated as first-class citizens. That is to say that functions have the same properties as values such as strings and integers. You can accomplish anything with a function that you would normally be able to do with a string or a number. This includes everything.
You might, for instance, give a function the responsibility of a variable. After that, you may make use of that variable in the exact same way that you would make use of the function.
itself:
>>>
1>>> def func():
2... print("I am function func()!")
3...
4
5>>> func()
6I am function func()!
7
8>>> another_name = func
9>>> another_name()
10I am function func()!
The creation of a new reference to func() under the name another name occurs with line 8’s assignment of another name = func. After that, you may invoke the function using either the given name, func, or another name, as shown on lines 5 and 9.
You may output a function to the console using the print() method, include it as a component in a composite data object like as a list, or even utilise it as if it were a dictionary.
key:
>>>
>>> def func():
... print("I am function func()!")
...
>>> print("cat", func, 42)
cat <function func at 0x7f81b4d29bf8> 42
>>> objects = ["cat", func, 42]
>>> objects[1]
<function func at 0x7f81b4d29bf8>
>>> objects[1]()
I am function func()!
>>> d = {"cat": 1, func: 2, 42: 3}
>>> d[func]
2
In this demonstration, the value func() is used in the identical situations as the values “cat” and 42, and the interpreter is able to process it without any problems. Note: The context plays a significant role in determining the abilities and restrictions associated with any given Python object. There are some procedures, for instance, that are only applicable to certain kinds of objects and not to others.
The plus operator (+) may be used to add two number objects, or it can be used to concatenate two string objects. But, function objects do not have a definition for the addition operator.
The fact that functions in Python match the two requirements useful for functional programming that were described above is the only thing that really counts for now. One function may be used as an argument in another function’s call.
argument:
>>>
1>>> def inner():
2... print("I am function inner()!")
3...
4
5>>> def outer(function):
6... function()
7...
8
9>>> outer(inner)
10I am function inner()!
This is what’s going on in the example up there:
example:
-
The call on line 9 passes
inner()
as an argument to
outer()
. -
Within
outer()
, Python binds
inner()
to the function parameter
function
. -
outer()
can then call
inner()
directly via
function
.
This phenomenon is referred to as function composition. As a point of clarification, Python’s decorators are a kind of shorthand notation that may be used to expedite the process of wrapping one function within another. Check out the “Primer on Python Decorators” if you want further information on this subject.
Because a call to the inner function can alter the behaviour of the outer function, the function that is passed to another function is sometimes referred to as a callback. This is because passing a function from one function to another function causes the passed-in function to be passed to the second function.
This is best shown by the sorted() function in the Python programming language. In most cases, the sorted() function will arrange the string values in lexical order if you provide it with a list of string values.
order:
>>>
>>> animals = ["ferret", "vole", "dog", "gecko"]
>>> sorted(animals)
['dog', 'ferret', 'gecko', 'vole']
sorted() does, however, accept a key argument as a second, optional parameter. This key argument defines a callback function that may be used as the sorting key. You might, for instance, rank things based on the length of the string.
instead:
>>>
>>> animals = ["ferret", "vole", "dog", "gecko"]
>>> sorted(animals, key=len)
['dog', 'vole', 'gecko', 'ferret']
sorted() has an additional, optional parameter that allows the user to specify sorting in the opposite direction. On the other hand, you may be able to do the same thing by implementing your own callback function that inverts the meaning of len ()
:
>>>
>>> animals = ["ferret", "vole", "dog", "gecko"]
>>> sorted(animals, key=len, reverse=True)
['ferret', 'gecko', 'vole', 'dog']
>>> def reverse_len(s):
... return -len(s)
...
>>> sorted(animals, key=reverse_len)
['ferret', 'gecko', 'vole', 'dog']
You may want to look at the How to Use page.
sorted(), as well as
sort() in Python is where you should go for further information on sorting data in Python.
In the same way that one function may receive another function as an input, another function can likewise be specified as the return value of another function.
value:
>>>
1>>> def outer():
2... def inner():
3... print("I am function inner()!")
4...
5... # Function outer() returns function inner()
6... return inner
7...
8
9>>> function = outer()
10>>> function
11<function outer.<locals>.inner at 0x7f18bc85faf0>
12>>> function()
13I am function inner()!
14
15>>> outer()()
16I am function inner()!
This is how the current situation stands:
example:
-
Lines 2 to 3:
outer()
defines a local function
inner()
. -
Line 6:
outer()
passes
inner()
back as its return value. -
Line 9:
The return value from
outer()
is assigned to variable
function
.
After this, you are able to use inner() in a roundabout manner by using function, as shown on line 12. It is also possible to make an indirect call to it by using the value that is returned by the outer() function without making an intermediary assignment, as seen on line 15.
As can be shown, Python already has the necessary components to provide adequate support for functional programming. Nevertheless, before you begin working with functional code, there is one more notion that will be beneficial for you to get familiar with; this concept is the lambda expression.
.
Defining an Anonymous Function With
Since functional programming is based entirely on calling functions and passing them to and from one another, it necessarily requires the definition of a large number of functions. You may always create a function in the standard method, using the def keyword as you have seen in other courses in this series. This is the easiest approach to write a function.
On the other hand, having the ability to create an anonymous function on the fly, without first having to give it a name, might be quite useful in some situations. A lambda expression is the tool you’ll need to do this in Python. Note of a technical nature: the name lambda originates from lambda calculus, which is a formal method of mathematical logic for defining computation based on the abstraction and application of functions.
The following is an example of the syntax for a lambda expression:
follows:
lambda <parameter_list>: <expression>
The following table provides a concise summary of the components that make up a lambda.
expression:
Component | Meaning |
---|---|
|
The keyword that introduces a
expression |
|
An optional comma-separated list of parameter names |
|
Punctuation that separates
from
|
|
An expression usually involving the names in
|
A callable function is returned as the value of a lambda expression, exactly way a function is when the def keyword is used to define it. It takes in input, which is represented by the parameter list> element, and it gives out output, which is denoted by the expression> element.
First, a little remark here.
example:
>>>
1>>> lambda s: s[::-1]
2<function <lambda> at 0x7fef8b452e18>
3
4>>> callable(lambda s: s[::-1])
5True
The lambda expression is going to be used as the statement on line 1, all by itself. Python will show the value of the expression on line 2, which as you can see is a function.
If the argument that is supplied to the built-in callable() method in Python looks to be callable, then the function will return True, and otherwise it will return False. Lines 4 and 5 demonstrate that the value that was returned by the lambda expression may in fact be called, just as it should be expected of a function.
In this particular instance, the parameter list is made up of only a single parameter s. Slicing syntax is used in the succeeding phrase s[::-1], which yields the characters in
s in reverse sequence . So, this lambda expression denotes a temporary function that does not have a name. This function accepts a string argument and returns the same string but with the characters in the opposite order.
The object that is produced by a lambda expression is a first-class citizen in the Python programming language, the same as a regular function or any other object. You may put it into a variable, and then use that variable to make a call to the function.
name:
>>>
>>> reverse = lambda s: s[::-1]
>>> reverse("I am a string")
'gnirts a ma I'
This is essentially comparable to creating reverse() using the def keyword, if you will pardon the pun.
keyword:
>>>
1>>> def reverse(s):
2... return s[::-1]
3...
4>>> reverse("I am a string")
5'gnirts a ma I'
6
7>>> reverse = lambda s: s[::-1]
8>>> reverse("I am a string")
9'gnirts a ma I'
Both the call on line 4 and the call on line 8 react exactly the same way.
But, before running a lambda expression, it is not required to first assign a variable to the expression. In addition to this, you may invoke the function that is defined by a lambda expression.
directly:
>>>
>>> (lambda s: s[::-1])("I am a string")
'gnirts a ma I'
Another one is this:
example:
>>>
>>> (lambda x1, x2, x3: (x1 + x2 + x3) / 3)(9, 6, 6)
7.0
>>> (lambda x1, x2, x3: (x1 + x2 + x3) / 3)(1.4, 1.1, 0.5)
1.0
In this particular instance, the parameters that are being used are x1, x2, and x3, and the expression that is being used is x1 + x2 + x3 / 3. The average of the three integers are going to be calculated using this lambda function, which is anonymous.
Another illustration of this would be to think back to when you wrote the function reverse len() as a callback for the sorting operation ()
:
>>>
>>> animals = ["ferret", "vole", "dog", "gecko"]
>>> def reverse_len(s):
... return -len(s)
...
>>> sorted(animals, key=reverse_len)
['ferret', 'gecko', 'vole', 'dog']
You may make use of a lambda function in this situation as well.
well:
>>>
>>> animals = ["ferret", "vole", "dog", "gecko"]
>>> sorted(animals, key=lambda s: -len(s))
['ferret', 'gecko', 'vole', 'dog']
In most cases, a lambda expression will include a parameter list, however this is not essential in all cases. A lambda function may be defined even if it doesn’t have any arguments. After then, the value that is returned is independent of any input.
parameters:
>>>
>>> forty_two_producer = lambda: 42
>>> forty_two_producer()
42
It is important to keep in mind that lambda may only be used to create very simple functions. One and only one expression may be used as the value that is returned by a lambda expression. It is not possible for a lambda expression to include statements like as assignment or return, nor can it contain control structures such as for, while, if, else, or def.
You discovered in the earlier lesson on creating a Python function that a function declared with def may effectively return several values. This was one of the key takeaways from that lesson. Python encapsulates the values and returns them in the form of a tuple if the return statement of a function has several values that are separated by commas.
:
>>>
>>> def func(x):
... return x, x ** 2, x ** 3
...
>>> func(3)
(3, 9, 27)
When applied to an anonymous function, this implicit tuple packing does not provide the desired results.
function:
>>>
>>> (lambda x: x, x ** 2, x ** 3)(3)
<stdin>:1: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma?
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
But, you are able to use a lambda function to return a tuple. All that is required of you is to explicitly indicate the tuple with parentheses. A lambda function may also be used to return an object type such as a list or dictionary.
function:
>>>
>>> (lambda x: (x, x ** 2, x ** 3))(3)
(3, 9, 27)
>>> (lambda x: [x, x ** 2, x ** 3])(3)
[3, 9, 27]
>>> (lambda x: {1: x, 2: x ** 2, 3: x ** 3})(3)
{1: 3, 2: 9, 3: 27}
Since a lambda expression has its own local namespace, the names of its parameters do not collide with any names that are exactly the same that are used in the global namespace. A lambda expression is able to read variables stored in the global namespace, but it is unable to make any changes to those variables.
One more peculiarity should be brought to your attention. In the event that you discover the need to include a lambda expression into a formatted string literal (f-string), then you will be required to encompass it in explicit quotes.
parentheses:
>>>
>>> print(f"--- {lambda s: s[::-1]} ---")
File "<stdin>", line 1
(lambda s)
^
SyntaxError: f-string: invalid syntax
>>> print(f"--- {(lambda s: s[::-1])} ---")
--- <function <lambda> at 0x7f97b775fa60> ---
>>> print(f"--- {(lambda s: s[::-1])('I am a string')} ---")
--- gnirts a ma I ---
You should now be familiar with the process of defining an anonymous function using lambda. Check out How to Use Python Lambda Functions for more information on lambda functions and other related reading material.
After that, it’s time to start delving into Python’s functional programming. When it comes to developing functional code, you’ll notice that lambda functions are very helpful and handy.
The functional programming paradigm may be implemented in Python via the use of two built-in methods called map() and filter(). The third, reduce(), is a function that is no longer a part of the core language but may still be used via a package known as functools. Each of these three functions incorporates a different function as one of its components.
arguments.
Applying a Function to an Iterable With
The first function to be executed is called map(), and it is a built-in function that is included with Python. You may apply a function to each element in an iterable in turn using the map() function, and map() will return an iterator that gives the results of those function applications. Since a map() statement may often take the place of an explicit one, this can make it possible to write code that is quite succinct.
loop.
Calling
When applied to a single iterable, the syntax for invoking map() looks like this:
this:
map(<f>, <iterable>)
map(f, iterable) is a function that returns an iterator that produces the results of applying the function f to each individual element of the iterable.
This is only one example. Let’s say you’ve created a method called reverse(), which accepts a string as an input and returns that string in the other direction by calling upon your trusted [::-1] string slicing operator.
mechanism:
>>>
>>> def reverse(s):
... return s[::-1]
...
>>> reverse("I am a string")
'gnirts a ma I'
If you have a list of strings, you may use the map() function to apply the reverse() function to each individual item in the list.
list:
>>>
>>> animals = ["cat", "dog", "hedgehog", "gecko"]
>>> iterator = map(reverse, animals)
>>> iterator
<map object at 0x7fd3558cbef0>
However keep in mind that the map() function does not yield a list. This action gives you back an iterator that is known as a map object. Either iterating over the iterator itself or making use of a list is required in order to acquire the iterator’s values ()
:
>>>
>>> iterator = map(reverse, animals)
>>> for i in iterator:
... print(i)
...
tac
god
gohegdeh
okceg
>>> iterator = map(reverse, animals)
>>> list(iterator)
['tac', 'god', 'gohegdeh', 'okceg']
It is possible to get the items from the initial list animals by iterating over the iterator and using the reverse() function on each string.
In this demonstration, reverse() is a rather brief method, and it’s possible that, apart from its use with map(), you won’t ever need it again. You could use an anonymous lambda function instead of adding a useless function to the code, which would result in less code bloat.
instead:
>>>
>>> animals = ["cat", "dog", "hedgehog", "gecko"]
>>> iterator = map(lambda s: s[::-1], animals)
>>> list(iterator)
['tac', 'god', 'gohegdeh', 'okceg']
>>> # Combining it all into one line:
>>> list(map(lambda s: s[::-1], ["cat", "dog", "hedgehog", "gecko"]))
['tac', 'god', 'gohegdeh', 'okceg']
Python will throw an exception in this case because the iterable may include things that aren’t appropriate for the function that was supplied.
:
>>>
>>> list(map(lambda s: s[::-1], ["cat", "dog", 3.14159, "gecko"]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
TypeError: 'float' object is not subscriptable
In this particular instance, the lambda function anticipates receiving a string as a parameter, which it then makes an attempt to slice. 3.14159 is the second item in the list, and it is an instance of the float data type, which cannot be sliced. As a result, a TypeError is generated.
Here’s an example that’s a little bit more applicable to real life: while you were learning about built-in string methods in the tutorial, you came across the str.join() function, which concatenates strings from an iterable, separated by the provided character.
string:
>>>
>>> "+".join(["cat", "dog", "hedgehog", "gecko"])
'cat+dog+hedgehog+gecko'
If the items in the list are strings, then this works just well. In the event that they are not, str.join() will throw a TypeError.
exception:
>>>
>>> "+".join([1, 2, 3, 4, 5])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: sequence item 0: expected str instance, int found
A loop is one potential solution to this problem. You may generate a new list from the numbers in the first list by using a for loop to do so. This new list will include string representations of the numbers. After that, you may send the newly created list to the.join function ()
:
>>>
>>> strings = []
>>> for i in [1, 2, 3, 4, 5]:
... strings.append(str(i))
...
>>> strings
['1', '2', '3', '4', '5']
>>> "+".join(strings)
'1+2+3+4+5'
On the other hand, given that the map() method sequentially applies a function to each item in a list, it may often obviate the need for an explicit loop. In this scenario, you may apply str() on the list objects using map() before combining the lists together.
them:
>>>
>>> "+".join(map(str, [1, 2, 3, 4, 5]))
'1+2+3+4+5'
map() produces an iterator that provides the list of string objects [“1”, “2”, “3”, “4”, “5”], and you can then successfully send that list to.join(). map() returns an iterator that yields the list of string objects [“1”, “2”, “3”, “4”, “5”].
In spite of the fact that map() was able to provide the intended result in the preceding example, it would be more appropriate to use a list comprehension in lieu of the explicit loop in a scenario such as the one described.
this.
Calling
There is yet another implementation of map() that accepts a number of iterables.
argument:
map(<f>, <iterable₁>, <iterable₂>, ..., <iterableₙ>)
map(f>, iterable 1 >, iterable 2 >,…, iterable n >) applies f> to the items in each iterable I > in parallel and returns an iterator that gives the results. This function may be used to apply f> to any number of iterables.
It is essential that the number of ‘iterable I > parameters supplied to map() correspond exactly to the number of arguments that ‘f> anticipates receiving. The outcome of applying f on the first item of each iterable I is what will be returned by the return iterator as the first item in the subsequent iterations. Then, ‘f’ operates on the second item in each ‘iterable I and the result is the second item that is delivered. This continues until all of the items have been processed.
An illustration ought to be helpful.
clarify:
>>>
>>> def f(a, b, c):
... return a + b + c
...
>>> list(map(f, [1, 2, 3], [10, 20, 30], [100, 200, 300]))
[111, 222, 333]
In this particular scenario, the function f() expects three parameters. In the same manner, map() accepts three iterable inputs, which are the lists [1, 2, 3], [10, 20, 30], and [100, 200, 300].
Applying f() on the first item in each list produces the following result: f(1, 10, 100). This results in the first item being returned. The following graphic demonstrates that the second item that was returned is f(2, 20, 200), and the third item that was returned was f(3, 30, 300):
An iterator that eventually produces the list [111, 222, 333] is the result that is returned by the map() function.
You could easily replace f() with a lambda function in this scenario as well due to the fact that it is such a short function.
instead:
>>>
>>> list(
... map(
... (lambda a, b, c: a + b + c),
... [1, 2, 3],
... [10, 20, 30],
... [100, 200, 300]
... )
... )
This illustrative usage of lambda makes use of additional parentheses surrounding the function, as well as implicit line continuation. Both are optional, however they both assist make the code simpler to understand.
read.
Selecting Elements From an Iterable With
The filter() function enables you to choose or filter items from inside an iterable depending on the evaluation of the function that is provided. It is referred to as
follows:
filter(<f>, <iterable>)
The filter(‘f’, ‘iterable’) command applies the function ‘f’ to each item in the ‘iterable’ array and returns an iterator that delivers all items that satisfy the condition ‘f’ if it is true. On the other hand, it eliminates from consideration any and all objects for which f is false.
In the following example, greater than 100(x) returns true if the value of x is larger than 100.
:
>>>
>>> def greater_than_100(x):
... return x > 100
...
>>> list(filter(greater_than_100, [1, 111, 2, 222, 3, 333]))
[111, 222, 333]
In this particular scenario, the greater than 100() function returns true for things 111, 222, and 333; hence, these items are kept, but items 1, 2, and 3 are thrown away. Similar to the functions shown in the examples that came before it, greater than 100() is a brief function that may be interchanged with a lambda expression.
instead:
>>>
>>> list(filter(lambda x: x > 100, [1, 111, 2, 222, 3, 333]))
[111, 222, 333]
The range() function will be used in the following example. It is possible to get an iterator that returns the integers ranging from 0 to n minus 1 by using the range(n) function. The following code demonstrates how to use filter() to exclude the odd integers from a list and pick just the even ones to display.
numbers:
>>>
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> def is_even(x):
... return x % 2 == 0
...
>>> list(filter(is_even, range(10)))
[0, 2, 4, 6, 8]
>>> list(filter(lambda x: x % 2 == 0, range(10)))
[0, 2, 4, 6, 8]
This is an example utilising a string that is already built into the system.
method:
>>>
>>> animals = ["cat", "Cat", "CAT", "dog", "Dog", "DOG", "emu", "Emu", "EMU"]
>>> def all_caps(s):
... return s.isupper()
...
>>> list(filter(all_caps, animals))
['CAT', 'DOG', 'EMU']
>>> list(filter(lambda s: s.isupper(), animals))
['CAT', 'DOG', 'EMU']
You may recall from the earlier lesson on string methods that s.isupper() returns True if all of the alphabetic letters in s are in the uppercase form, while it returns False otherwise.
otherwise.
Reducing an Iterable to a Single Value With
The reduce() function applies a function to the elements in an iterable two at a time, gradually consolidating those elements into a single result in the process.
reduce() was a built-in function in Python at one point in time. It would seem that Guido van Rossum had some serious issues with the reduction() function, since he pushed for its complete exclusion from the language. The following is what he had to say in response to it:
The next step is reduce(). Because, with the exception of a few examples involving + or *, almost every time I see a reduce() call with a non-trivial function argument, I need to grab a pen and paper to diagram what is actually being fed into that function before I can understand what the reduce() function is supposed to do. This is the one I’ve always hated the most. So, in my opinion, the functionality of reduce() is almost entirely limited to that of associative operators; in all other circumstances, it is preferable to write the accumulation loop out manually. ( Original Language)
Actually, Guido supported the idea of removing all three of Python’s reduce(), map(), and filter() functions from the language. The only thing one can do is speculate about his motivations. It just so happens that the list comprehension that was discussed before encompasses not just the functionality that is offered by all of these methods but also a great deal more. Reading When to Use a List Comprehension in Python will provide you with further information that you can use.
As you can see, the map() and filter() built-in methods will continue to be available in Python. You won’t find the reduction() function as a built-in option any more; but, as you’ll see in the next section, the function may be imported from a standard library module.
In order to make use of the reduction() function, you will need to import it from a module known as functools. This may be accomplished in a few different methods, but the most common ones are as follows:
straightforward:
from functools import reduce
After this, the interpreter inserts the reduction() function into the global namespace and makes it accessible for usage. The examples that follow will take for granted that this is the case.
case.
Calling
As can be seen in the example, the reduce() method only requires one function and one iterable to be called.
below:
reduce(<f>, <iterable>)
reduce(‘f>, ‘iterable>’) utilises ‘f>, which must be a function that takes exactly two parameters, to gradually combine the components in ‘iterable>. f must be a function that takes exactly two arguments. The function reduce() begins by calling the function f on the iterable’s first two items. Next, that result is combined with the third component, followed by that result’s combination with the fourth component, and so on and so forth until the list is depleted. The ultimate outcome is what reduce() hands back to you.
When Guido claimed that the applications of reduce() that use associative operators are the simplest, he was absolutely correct. Let’s begin with the plus sign (+) and go on from there.
):
>>>
>>> def f(x, y):
... return x + y
...
>>> from functools import reduce
>>> reduce(f, [1, 2, 3, 4, 5])
15
Because of this call to reduce(), the result 15 is generated from the list [1, 2, 3, 4, 5] in the following way:
reduce(f, [1, 2, 3, 4, 5]) (f, [1, 2, 3, 4, 5])
Calculating the total of the numbers in the list using this approach is somewhat circuitous! Although this does work, there is a more straightforward approach. The built-in sum() function of Python calculates and returns the total value of the numbers in an array.
iterable:
>>>
>>> sum([1, 2, 3, 4, 5])
15
It is important to keep in mind that the binary addition operator may also concatenate strings. So, this identical example will concatenate the strings in a list one by one as they are added.
well:
>>>
>>> reduce(f, ["cat", "dog", "hedgehog", "gecko"])
'catdoghedgehoggecko'
Again, there is a method for achieving this goal that the majority of people would consider to be more “Pythonic.” This is exactly what the str.join command does ()
does:
>>>
>>> "".join(["cat", "dog", "hedgehog", "gecko"])
'catdoghedgehoggecko'
Have a look at the following example, which makes use of the binary multiplication operator (*). The following formula may be used to determine the factorial of any positive integer n:
As illustrated, a factorial function may be implemented by utilising the reduce() and range() functions.
below:
>>>
>>> def multiply(x, y):
... return x * y
...
>>> def factorial(n):
... from functools import reduce
... return reduce(multiply, range(1, n + 1))
...
>>> factorial(4) # 1 * 2 * 3 * 4
24
>>> factorial(6) # 1 * 2 * 3 * 4 * 5 * 6
720
One more time, there is a method that is less complicated to do this task. You are free to make use of the factorial() function that is offered by the standard maths module.
:
>>>
>>> from math import factorial
>>> factorial(4)
24
>>> factorial(6)
720
As a last example, let’s say you need to determine which item in a list has the highest value. For this purpose, Python’s built-in maximum function, max(), is available, but you may also utilise the reduce() method.
well:
>>>
>>> max([23, 49, 6, 32])
49
>>> def greater(x, y):
... return x if x > y else y
...
>>> from functools import reduce
>>> reduce(greater, [23, 49, 6, 32])
49
Take note that the function that was supplied to reduce() in each of the examples shown above was a one-line function. In each scenario, you had the option of using a lambda function.
instead:
>>>
>>> reduce(lambda x, y: x + y, [1, 2, 3, 4, 5])
15
>>> reduce(lambda x, y: x + y, ["foo", "bar", "baz", "quz"])
'foobarbazquz'
>>> def factorial(n):
... from functools import reduce
... return reduce(lambda x, y: x * y, range(1, n + 1))
...
>>> factorial(4)
24
>>> factorial(6)
720
>>> reduce((lambda x, y: x if x > y else y), [23, 49, 6, 32])
49
This is a handy approach to avoid putting a function into the namespace that would not be required under normal circumstances. If, on the other hand, you use lambda rather of writing a distinct function, the person who is reading your code may have a more difficult time understanding what you want to do. Readability and accessibility must be balanced, as is so often the case.
convenience.
Calling
There is one more way to invoke the reduce() function, and this method allows the user to provide a beginning value for the reduction.
sequence:
reduce(<f>, <iterable>, <init>)
When present, the init> tag requires a value to be specified as the combination’s initial value. When function f is called for the first time, its parameters are ‘init’ and the item that comes first in the iterable. After that, the result is merged with the second component of the iterable, and as a consequence,
on:
>>>
>>> def f(x, y):
... return x + y
...
>>> from functools import reduce
>>> reduce(f, [1, 2, 3, 4, 5], 100) # (100 + 1 + 2 + 3 + 4 + 5)
115
>>> # Using lambda:
>>> reduce(lambda x, y: x + y, [1, 2, 3, 4, 5], 100)
115
The following is the current format for the sequence of function calls:
reduce(f, [1, 2, 3, 4, 5], 100) (f, [1, 2, 3, 4, 5], 100)
It would not be difficult for you to do the same thing without using reduce ()
:
>>>
>>> 100 + sum([1, 2, 3, 4, 5])
115
As you have seen in the preceding examples, even in situations in which it is feasible to complete a job by using reduce(), it is often able to discover a method that is both more clear and more native to Python for doing the same work without using reduce(). After all, the reason reduce() was taken out of the core language may not be as mysterious as it first seemed.
That being said, the reduce() method is really spectacular in its own right. reduce() is described as being able to aggregate several items into a single result in the introduction to this subsection. But, that outcome may take the form of a composite object, such as a list or a tuple. Because of this, reduce() is a fairly broad higher-order function that may be used as a starting point for the implementation of a wide variety of other functions.
Take map() as an example; you might write it using reduce instead ()
:
>>>
>>> numbers = [1, 2, 3, 4, 5]
>>> list(map(str, numbers))
['1', '2', '3', '4', '5']
>>> def custom_map(function, iterable):
... from functools import reduce
...
... return reduce(
... lambda items, value: items + [function(value)],
... iterable,
... [],
... )
...
>>> list(custom_map(str, numbers))
['1', '2', '3', '4', '5']
You may implement the filter() method using the reduce() method instead.
well:
>>>
>>> numbers = list(range(10))
>>> numbers
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> def is_even(x):
... return x % 2 == 0
...
>>> list(filter(is_even, numbers))
[0, 2, 4, 6, 8]
>>> def custom_filter(function, iterable):
... from functools import reduce
...
... return reduce(
... lambda items, value: items + [value] if function(value) else items,
... iterable,
... []
... )
...
>>> list(custom_filter(is_even, numbers))
[0, 2, 4, 6, 8]
In point of fact, a reduction may be used to represent any action carried out on a series of objects.