Lets move onto decorators with the above concepts in mind.
DecoratorsUsing the above concepts, we can create a decorator which is nothing but a function wrapped around another function.
Lets consider a function that wraps the output of another function:Fig5: Decorating a function using another functionNotice how in the above example we are using the concept of inner function using the enclosed scope of outer function.
Here we are using the lets_decorate function and passing get_txt function as a parameter to it.
lets_decorate function returns func_wrapper which gets assigned to my_output variable.
When we make a call to my_output variable by passing in a parameter we get the output.
The output which we get augments the output of get_txt function (which is actually called inside the func_wrapper function), hence decorating it.
I know its a little confusing at first, but if you give it a little thought, its actually a mixture of all the concepts we discussed in the above basics.
Fortunately, python provides a better way of creating & using decorators through some syntactic sugar:Fig6: Creating and using decorators in python using syntactic sugarWe can see how the decorator lets_decorate is used on the function get_txt by prepending ‘@’ symbol to the decorator, kind of a shortcut method of using decorators on a function.
Decorating MethodsMethods expect their first parameter to be self, a reference to the current object.
We can build decorators for methods in the same way as above by taking self into consideration.
Lets see an example:Fig7: Using decorators on methodsAnother and better approach would be to make our decorator useful for functions and methods alike.
Fig8: Using decorators on methods with args and kwargs as parametersargs and kwargs can be used to as parameters for the wrapper so that it can accept any arbitrary number of arguments and keyword arguments.
You can learn more about args and kwargs here.
Passing arguments to decoratorsWe can also pass arguments to a decorator.
Decorators expect to receive a function as an argument and that is why to pass an argument, we will have to build a function that takes those extra arguments and generate our decorator.
Fig9: Passing argument to a decoratorThe use of functoolsLets try to debug the get_txt function above which has been decorated:Fig10: Decorator overrides the attributes of a functionAs you can see instead of printing get_txt, we get the output as func_wrapper.
So when a function is decorated, its attributes get overridden by those of the wrapper.
We use functools module which contains functools.
wraps to avoid this overriding of the attributes of a function getting decorated.
Wraps is a decorator for updating the attributes of the wrapping function func_wrapper to those of the original function get_txt.
This is as simple as decorating func_wrapper by @wraps(func).
Fig11: Using wraps to maintain the attributes of the function being decoratedUse of DecoratorsWhat we have covered till now is just the basics of how we can use decorators.
There are a ton of things which can be done using decorators as they provide the power and elegance to your program by helping us to extend the behavior of functions and methods which we dont want to modify.
More reading resourcesHere is a list of other resources worth checking out:What is a decorator?Decorators I: Introduction to Python DecoratorsPython Decorators II: Decorator ArgumentsPython Decorators III: A Decorator-Based Build SystemHope you find this post helpful for writing your libraries in python.
You can share your views and concerns in the comments section.