How to Use Python Decorators and Why?
|In this Python article, we will discuss decorators, their uses, and how to use decorators using few examples. Let’s begin.
1. What is a Decorator?
The modification of properties and behavior of a class or a function can be extended according to the requirement, such modification is made with the help of Decorators.
By definition, a decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it.
With the help of decorators, one can easily wrap any other function for extending the behavior and properties of the wrapped function, these modifications are not permanent.
This is also known as metaprogramming as it involves the modification of one part of the program with the help of another part of the program during the time of compilation.
Syntax: @any_decorator def decorator_name(): statements '''Above code is similar to: def decorator_name(): statements decorator_name = any_decorator(arguments)'''
The syntax shows the use of any_decorator
as a function which can be called, on the top of any other callable function, it will add decorator_name
function and it returns the wrapper function.
It is important to note that decorators do not change the behavior of the decorated function, it simply adds some functionality on top of the existing one.
Let’s discuss some of the important concepts before going deep into the decorators which will help in understanding decorators better.
1.1. What is meant by First class Object?
We term any function as a first-class object when the function can be used or passed as arguments.
Characteristics of first-class functions:
- The function will be an object type instance.
- The function can be stored inside a variable.
- The function can be passed to other function as a parameter.
- The function can be returned from a function.
- The function can be stored in different data structures (hash tables, lists,etc).
1.2. Function as an Object
Let’s take an example to understand the function as an object in python.
# function as objects def readout(message): return message.lower() read_me = readout print(readout('CODINGEEK!')) print(read_me('CODINGEEK!'))
Output codingeek! codingeek!
The above example demonstrates the assigning of the function readout
to a variable read_me
. This tells us that functions in Python are an object like everything else (Yes, that’s correct everything in Python is an Object).
Here read_me
and readout
are just two different names(variables) pointing to the same object.
1.3. Function as an Arguments
Let’s take an example to understand function as arguments.
#function passed as argument to another function def readme_soft(message): return message.lower() def readme_loud(message): return message.upper() def positive_message(inp_func): # function is stored in variable print("Decorating the function..") pm = inp_func("Good news, you are learning python advance.") print (pm) positive_message(readme_loud) positive_message(readme_soft)
Output Decorating the function.. GOOD NEWS, YOU ARE LEARNING PYTHON ADVANCE. Decorating the function.. good news, you are learning python advance.
The above example illustrates positive_message
is taking another function readme_loud
and readme_soft
as parameters. We also extended the functionality of method positive_message
, which means we decorated that message.
Inside the function positive_messge
, we call the functions which are passed as arguments.
1.4. Return Function from Function
This time, let’s take one more example to understand the returning of the function to another function or Python Closures.
# Functions can return another function def subtract(val1): def sub(val2): return val1-val2 return sub sub_val = subtract(174) print(sub_val(121))
Output 53
Finally, we have understood the important concepts using the three programs which were prerequisites to understand decorators.
Let’s discuss decorators now.
2. Using Decorators
We have discussed that decorators can add additional behavior to the existing method.
Now, let’s take an example to understand how does it actually work.
def new_decorator(inp_function): # decorator definition '''Here inside_decorator is a Wrapper function where the argument will be passed''' '''local functions can be accessed by inner function here example "inp_function''' def inside_decorator(): print("I am inside the decorator") # calling actual function inside the wrapper function. inp_function() print("I have successfully made my execution") return inside_decorator # function, for being called inside wrapper def calling_function(): print("This is the main content!") # passing 'calling_function' inside decorator for controlling its behavior calling_function = new_decorator(calling_function) # function call calling_function()
Output I am inside the decorator This is the main content! I have successfully made my execution
In the above example, first the passing of calling_function
will run, it will call the new_decorator
followed by inside_decorator
and then directly returning the inside_decorator
.
Now the second calling_function
will run and all the functions inside the new_decorators
along with the inp_function
and all the remaining print statements will be executed and the program will finish.
2.1. Decorator with Generic Method Arguments
There must be a question in mind, can the decorator find the time of execution? Well, the answer is ‘Yes’, we can use a decorator to find the execution time. This is just one real-world example and there can be a lot more.
Let’s understand how to calculate the method execution time with an example.
import time def getme_time(inp_function): """decorator to calculate time duration for execution of function.""" def inside_decorator(*args, **kwargs): """ added arguments inside the inner1, if function takes any arguments, can be added like this. """ start_time = time.time() inp_function(*args, **kwargs) stop_time = time.time() print("Time taken for execution : ", inp_function.__name__, stop_time - start_time) return inside_decorator @getme_time def multiply(value1, value2): time.sleep(1) value = value1 * value2 print(value) # function call multiply(12, 5)
Output 60 Time taken for execution : multiply 1.0012080669403076
In the above example, you may notice a keen difference in the parameters of the inner function. The inner function takes the argument as *args and **kwargs which means that a tuple of positional arguments or a dictionary of keyword arguments can be passed of any length. This makes it a general decorator that can decorate a function having any number of arguments.
If we do not want to use *args and **kwargs then we have to keep the arguments the same both for the decorated function and the nested function of the decorator.
3. Chaining of Dcorators in Python
Python allows users to chain multiple decorators.
In simpler terms, it means that we can decorate one function multiple times with the same or different decorator(s) as per the requirement and use.
This can be done by simply putting the decorator above any particular function.
The benefit of using the chaining method is that it makes the decorators more useful for developing reusable blocks as it collects different effects together.
Chaining multiple decorators is also known as nested decorators in Python.
def first_decorator(func_name): def inside_function(): print("First Decorator") func_name() return inside_function def second_decorator(func_name): def inside_function(): print("Second Decorator") func_name() return inside_function @first_decorator @second_decorator def passvalue(): print("Decorated function") passvalue()
Output First Decorator Second Decorator Decorated function
In the above program, the function passvalue
pass value 5 to both the defined function that is first_decorator
and second_decorator
.
The function called is equivalent to first_decorator(second_decorator(passvalue()))
and hence the order of annotations matter.
4. Conclusion
Finally, if we sum up, in this article we covered everything about decorator which was necessary and important along with different program implementation, we have covered:
- What is a Decorator and why do we need a decorator in Python.
- What is meant by First class Object in python?
- How can we use Decorators?
- How to make chaining of decorator in Python?
Helpful Links
Please follow the Python tutorial series or the menu in the sidebar for the complete tutorial series.
Also for examples in Python and practice please refer to Python Examples.
Complete code samples are present on Github project.
Recommended Books
An investment in knowledge always pays the best interest. I hope you like the tutorial. Do come back for more because learning paves way for a better understanding
Do not forget to share and Subscribe.
Happy coding!! ?