In this post, we will investigate the concept of Higher Order Functions in Python. These are functions that take as a parameter, or return (or both), a function.
Higher Order Function Concepts
Given that we can assign a reference into a function to a variable; then this might imply that we can also use the same approach to pass a reference to a function as an argument to another function.
This implies that one function can accept another function as a parameter. Such functions are known as higher order functions and considered as one of the key constructs in functional programming. In other words, a function that takes another function as a parameter is known as a higher order function.
In fact, in Python, higher order functions are functions that do a minimum of one among the subsequent (and may do both):
- take one or more functions as a parameter
- return as a result a function
All other functions in Python are considered to be the first-order functions. Many of the functions found in the Python libraries are higher order functions. It is a common enough pattern that once we are aware of it we will recognize it in many different libraries.
Higher Order Function Example
As an abstract example, consider the following higher order function apply. This function (written in pseudo-code; not a real programming language) takes an integer and a function. Within the body of the function being defined, the function passed in as a parameter is applied to the integer parameter. The result of the function being is then returned.
def apply(x, function): return = function(x) result result
The function apply is a higher order function because its behavior (and its result) will depend on the behavior defined by another function; the one passed into it. We could also define a function that multiplies a number by 5, for example,
def mult(y): return y * 5
Now, we can use the function mult with the function apply, as shown below.
apply (10, mult)
This gives the output as 50.
Python Higher Order Functions
As we’ve already seen once we define a function it actually creates a function object that’s referenced by the name of the function. For example, if we create the function mult_by_two
def mult_by_two(num): return num * 2
Then this has created a function object referenced by the name mult_by_two that we can invoke using the round brackets (parenthesis). It is also a parameter function that takes variety and returns a worth which is twice that number.
Thus, a parameter that expects to be given a reference to a function that takes a number and returns a number can be given a reference to any function that meets this contract. This includes our (mult_by_two) function but also any of the following.
def mult_by_five(num): return num * 5 def square(num): return num * num def add_one(num): return num + 1
All of the above could be used with the following higher order function.
def apply(num, func): return func(num)
result = apply(10, mult_by_two) print(result)
The output from this code is 20. The following listing provides a complete set of the earlier sample functions and how they may be used with the apply function.
print (apply(10, mult_by_five)) print (apply(10, square)) print (apply(10, add_one)) print (apply(10, mult_by_two))
The result for the above code snippet will be
50 100 11 20
Using Higher Order Functions
Looking at the previous section; you’ll be wondering why we might want to use a higher order functions or indeed why define one. After all, could we not have called one among the functions directly by passing within the integer to used. We could have done
square(10) and this is able to have precisely the same effect as calling
The first approach seems to simpler and more efficient. The key to use the higher order functions is to think about what would happen if we all know that some function should be applied to the value 10 but we don’t yet know what it is. The particular function is provided at some point in the future. We create a reusable piece of code which will be ready to apply an appropriate function to the data we’ve when that function is known.
For example, let us assume that we wish to calculate the quantity of tax someone should pay supported their salary. However, we don’t know how to calculate the tax that this person must pay as it is dependent on external factors. The
calculate_tax function could take an appropriate function that performs that calculation and provides the acceptable tax value.
calculate_tax does not know how to calculate the particular tax to be paid; instead a function must be provided as a parameter to the
calculate_tax() function. The function passed in takes a number and return the results of performing the calculation. It’s used with the salary parameter also passed into the
import math def simple_tax_calculator (amount): return math.ceil(amount * 0.3) def calculate_tax (salary, func): return func(salary) print (calculate_tax(45000.0, simple_tax_calculator))
Finally, it prints out the tax calculated with the output of 13500.
Functions Returning Functions
In Python, as well as passing a function into another function; functions can be returner from a function. This can be used to select amongst a number of different options or to create a new function based on the parameters.
For example, the following code creates a function that can be used to check whether a number is even, odd or negative based on the string passed into it.
def make_checker(s): if s == 'even': return lambda n: n%2 == 0 elif s == 'positive': return lambda n: n>= 0 elif s == 'negative': return lambda n: n< 0 else: raise ValueError('Unknown request')
Note the use of the raise ValueError; for the moment we will just say that this is a way of showing that there is problem in the code; which may occur if this function is called with an inappropriate parameter value for ‘s’.
This function is a factory for functions that can be created to perform specific operations. It is used below to make three functions which will validate what type a number is
f1 = make_checker('even') f2 = make_checker('positive') f3 = make_checker('negative') print(f1(3)) print(f2(3)) print(f3(3))
Of course, it’s not only anonymous functions which will be returned from a function; it’s also possible to return a named function. This is finished by returning only the name of the function (i.e. without the round brackets).
def make_function(): def adder(x, y): return x + y return adder f1 = make_function() print(f1(3,2)) print(f1(3,3)) print(f1(3,1))
The result for above code snippet is
5 6 4
You can also check —>