Decorators
In simple words, Decorator is a function that calls another function.
Decorators are very useful concept in Python. Decorators allow the programmers to enhance the functionality of a function by wrapping it with a decorator.
It is similar to having a function with in a function. Before we see more about decorators let's have a quick look at how it is like to wrap a function within another function and how a function can be assigned like an object. These will help in understanding the decorators better.
Assigning function as an Object
Like creating instance of a class (object), the same can be done with functions as well.
We can define a function and create instances of a function. Function can either be called directly or by using the instance created.
Result
In the above example,
- Line - 2: Defining 'hello_world' function without any arguments.
- Line - 7: Calling the function 'hello_world'.
- Line - 10: Assigning the function 'hello_world' with a different name 'say_hello'.
- One thing to note here is while assigning a function to create an instance, We should not specify round brackets after the function name.
- Mentioning the round brackets would call the function and assigns the return value to the variable.
- Line - 13: Print statement before calling the instance of a function.
- Line - 14: Calling the function 'say_hello' which also executes the functionality provided with in 'hello_world'.
One thing to note here is, assigning the function would create a new function and would be able to execute even after the deletion of the original function.
Wrap a function with another function
Let's have a look at creating a function to wrap another function. This is usually required when the wrapper function need to contain some additional functionality.
Result
In the above example,
- Line - 2: Defining the 'hello_world' function which just prints a message.
- Line - 7: Defining another function 'say_hello' with some additional messages.
- Lines - 8 & 10: To understand better, We are only printing Start and End of a wrapper function.
- Line - 9: Calling 'hello_world' function, which prints "Hello World" message.
- Line - 14: Calling 'say_hello' function to call 'hello_world' with added functionality from wrapper function.
This is easy and straight forward. However, if we need to create a wrapper for 10 functions or even more, we would need to create 10 different functions.
Passing Function as parameter to wrapper function
One solution for this is passing function as a parameter. Let's have a look at an example by having two different functions and one wrapper function.
Result
In the above example,
- Line - 2 & 6: Two different functions defined with different message to be printed.
- Line - 11: Defining a wrapper function 'say_hello' by passing a function as an argument.
- 'new_function' is an argument and function can be called by using this name.
- Line - 13: Calling the function by using the name mentioned in the arguments.
- Function called would be the function passed.
- Line - 18: Call function 'say_hello' and pass function 'hello_world' as an argument.
- One thing to note here, round brackets should not be used after the function in the arguments.
- Line - 21: Call function 'say_hello' and pass function 'hello' as an argument.
- One thing to note here, round brackets should not be used after the function in the arguments.
However, Where ever the original function is called, the code need to be modified to call wrapper function instead.
This can be avoided by using decorators.
Creating a decorator
Using decorators makes this process much easier.
- Decorators can be used with functions that require arguments.
- Calling programs doesn't require to be modified to call the new wrapper function.
- Same decorator can be with different functions.
Let's have a look at an example of a decorator for a function with no arguments.
Result
In the above example,
- Line - 1: Defining a decorator with a function as an argument.
- Decorator need to be mentioned against the function by using '@'.
- This function would be referred with the name in the arguments in the decorator.
- Line - 5: Defining a wrapper function with arguments needed for the original function to be called.
- No arguments passed in this case as the original function 'hello_world' doesn't require any arguments to be passed.
- Lines - 6 & 8: Print statements to print the message for beginning and end of decorator wrapper function. Can be any code required to be performed as part of wrapper function.
- Line - 7: Function call, with the function name passed in the arguments.
- Line - 10: Return of wrapper, name of the function (with out round brackets). This is required to execute the wrapper function defined inside decorator function.
- Line - 16: Defining the function 'hello_world'. There is no change in the way function is coded. If decorator needs to be used, this needs to be added before the function definition.
- Line - 15: Mentioning decorator against the function, name of the decorator function by prefixing with '@'.
- This makes the whole process easier compared to writing the wrapper to enclose the function directly.
- No change needs to be done in the way original function is called (Line - 23).
- If this line is removed, the original function call will only execute the function defined and not decorator.
- Line - 23: No change to be done in the calling program. This is a huge advantage when the function is being used in large number of programs.
Creating a decorator for a function with arguments
In the previous example, we have seen how to create a decorator for a function with no arguments.
So, How to deal with a function with arguments? Wrapper function inside the decorator needs to be created with the required arguments. Arguments passed to the original function would automatically be passed over to the wrapper function in decorator.
Result
In the above example, we have added an argument to the original function and the wrapper function.
- Line - 16: Defining the function 'hello_world' with one argument. No change in the way decorator is mentioned before the function definition.
- Line - 5: Defining the wrapper function inside the decorator with the arguments needed. Arguments passed to the original function (Line - 23) will be passed over to the wrapper inside the decorator.
- Line - 23: Calling the the function by passing the required arguments.
There is no other change required to this process.
Creating a decorator for a function with return value
What if the function needs to return a value back to the calling program? Return value needs to be captured and returned at the end of the wrapper function.
One thing to note here is, if the return value is mentioned in middle of wrapper function, execution would stop there (like any other function).
Result
In the above example, we have only done couple of changes to include return statement in the original function and in the wrapper function.
- Line - 19: Adding a return statement inside the original function.
- Line - 7: Assigning the return value to the variable inside the wrapper function.
- Line - 9: Returning the value from the wrapper function. This would return the return value back to the calling function.
- Line - 25: Assigning the return value of the function. No change needs to be done for this when a decorator is added to the function.
Hope the above info was useful in understanding the how decorators work in Python.
If you have any Suggestions or Feedback, Please leave a comment below or use Contact Form.
well defined , easy to understand
ReplyDeleteThanks Sneha.
DeleteDecorator in the last example is useless. The same result without @say_hello_decorator. This decorator only adds one output string before and another string after "Hello World, Pradeep here." Not good example.
ReplyDeleteHi Andyrey,
DeleteThanks for sharing your inputs.
I meant to keep it simple and easy to understand with as much of coding as possible.
Thanks
Very well explained with simple examples. Keep up the good work!
ReplyDeleteThank you..
Delete