An Overview Of Python Decoratorsby Applied Informatics
Python is a rich and powerful language and is used by one of the popular sites in the world such as Youtube and Dropbox. The language design of python is such that it emphasizes more on code readability, allows to explain things faster than other languages and in lesser number of lines. Now, one of the main concepts used in python language is the use of Python Decorators.
Decorators dynamically alter the functionality of a function, method, or class without having to directly use sub-classes. This becomes necessary when we want to extend the functionality of a function without having to modify the function. Essentially, decorators work as wrappers, modifying the behavior of the code before and after a target function execution, without the need to modify the function itself, augmenting the original functionality, thus decorating it.
Composition Of Decorators
Decorators are simply wrappers to existing functions.We can create a decorator by following some of the basic function syntax. An example to show case the use of decorators can be done by a simple function that illustrates the time taken by a function to execute.
import time def timing_function(some_function): def wrapper(): t1 = time.time() some_function() t2 = time.time() return "Time it took to run the function: " + str((t2-t1)) + "\n" return wrapper @timing_function #using timing_function as decorator def my_function(): num_list =  for x in (range(0,100)): num_list.append(x) print "\nSum of all the numbers: " +str((sum(num_list))) print my_function()
This returns the time before you run my_function() as well as the time after. Then we simply subtract the two to see how long it took to run the function.
Similarly we can create another decorator and use it for rate limiting.
from time import sleep def sleep_decorator(function): """ Limits how fast the function is called. """ def wrapper(*args, **kwargs): sleep(2) return function(*args, **kwargs) return wrapper @sleep_decorator def number_print(num): return num print number_print(222) for x in range(1,6): print number_print(x)
Now depending upon the framework, whether Flask or Django, the decorators can be used accordingly. For illustration we can consider the decorator such as login_required() used in both Flask And Django.
This notion of wrapping a function with additional functionality without changing the wrapped function is extremely powerful and useful. Much can be done with decorators that would otherwise require lots of code or are not possible. They also act as a convenient way for frameworks and libraries to provide functionality. Flask uses decorators as a means for adding new endpoints to the web application, as in this example from the documentation:
from functools import wraps from flask import g, request, redirect, url_for def login_required(f): @wraps(f) def decorated_function(*args, **kwargs): if g.user is None: return redirect(url_for('login', next=request.url)) return f(*args, **kwargs) return decorated_function @app.route('/home') #specifies a url after a user is properly logged in/authenticated @login_required #login_required decorator def function<em>_</em>name(): pass
from django.contrib.auth.decorators import login_required @login_required(redirect_field_name='my_redirect_field') def my_view(request): """code that is to be executed in this function"""
Thus depending on the need of the code decorators can be used for anything that we want to wrap with additional functionality such as registering filter functions, wrapping the various functionality with a certain view, timing functions or simply access control. Decorators can be used to manipulate language and its powerful implications can change the behavior of a function.