Python
Topics:
Higher Order Functions and Decorators
• Getting Started
• Working with Data
• Object Oriented Programming
• Iterators and Generators
• Functional Programming

# Higher Order Functions and Decorators

• Tutorial

## Python Higher-Order Functions and Decorators

In Python, functions are treated as first class objects, allowing you to perform the following operations on functions.

• A function can take one or more functions as arguments
• A function can be returned as a result of another function

In this tutorial, you will learn:

1. Handling functions as arguments
2. Returning functions as the return value from other functions
3. Using closures and decorators


## Functions as arguments

You can pass functions as one of the arguments to another function. This is shown in the following example.

def summation(nums): # normal function
return sum(nums)

def main(f, *args): # function as an argument
result = f(*args)
print(result)

if __name__ == "__main__":
main(summation, [1,2,3]) # output 6


The main function took in the function summation as an argument. The main function is a normal function which executes the supplied function with the arguments. You can see that the output reflects that. This opens up possibilities where you can pass different functions to a function, and the passed function only will be considered.

## Having a function as a return value

def add_tw0_nums(x, y): # normal function which returns data
return x + y

def add_three_nums(x, y, z): # normal function which returns data
return x + y + z

def get_appropriate_function(num_len): # function which returns functions depending on the logic
if num_len == 3:
else:

if __name__ == "__main__":
args = [1, 2, 3]
num_len = len(args)
res_function = get_appropriate_function(num_len)
print(res_function)       # <function add_three_nums at 0x7f8f34173668>
print(res_function(*args)) # unpack the args, output 6

args = [1, 2]
num_len = len(args)
res_function = get_appropriate_function(num_len)
print(res_function)       # <function add_tw0_nums at 0x7f1630955e18>
print(res_function(*args)) # unpack the args, output 3


Here, you can see that different functions were returned depending on the argument in the “get_appropriate_function.”

## Python closures

Let’s now look at how closures are created in Python. A closure is a way of keeping alive a variable even when the function has returned. So, in a closure, a function is defined along with the environment. In Python, this is done by nesting a function inside the encapsulating function and then returning the underlying function.

def add_5():
five = 5

return arg + five

if __name__ == '__main__':
print(closure1(1)) # output 6
print(closure1(2)) # output 7


## Python decorators

Now, using the these ways of writing, Python code can be used to create decorators. Python decorators are convenient ways to make changes to the functionality of code without making changes to the code. A decorator is written as a function closure and implemented by giving the “@” operator on top of the function. The skeleton of a Python decorator is shown below.

def my_decorator(f):
# return the wrapping function
pass

@my_decorator
def my_code(args):
# original functionality
pass

my_code(args)


Using this skeleton as an example, giving the @ operator on top of the function is the same as writing my_decorator(my_code(args)).

You can look at the following example where you have a function that returns a dictionary.

def my_code(args):
return {lang: args}


Executing this code will give the normal result.

>>> def my_code(args):
...     return {"lang": args}
...
>>> print(my_code("python"))
{'lang': 'python'}
>>>


Say, you want to build the additional functionality of checking if the return value is a dict. In this case, you can use a decorator.

>>> def check(f):
...     def wrapper(*args, **kwargs):
...         res = f(*args, **kwargs)
...         if isinstance(res, dict):
...             print("checked that the return value is dict")
...             return res
...     return wrapper
...
>>>
>>>
>>> @check
... def my_code(args):
...     return {"lang": args}
...
>>> print(my_code("python"))
checked that the return value is dict
{'lang': 'python'}


Here, the function “check” is used as a decorator, and it enforces the additional functionality of checking if the return of the function ”my_code” is a decorator or not.

Contributed by: Joydeep Bhattacharjee