What are decorators in Python?
Decorator is a function that takes another function as an argument and extends the behavior of the later function without explicitly modifying it. In other words, decorator wraps another function in order to extend the behavior of wrapped function.
In decorators, function are taken as the argument into another function and then called inside the wrapper function. Let's consider following example to understand the concept of decorators:
Decorator Example
# check_divisor is decorator function
def check_divisor(func):
def inner(a,b):
if b==0:
return "Divison by zero is not possible."
return func(a,b)
return inner
# Here we are using decorator function
# to check whether there is division by zero or not
@check_divisor
def divide(a,b):
return a/b
print(divide(4,5))
print(divide(40,0))
print(divide(400,5))
print(divide(23.4,0))
Output
0.8 Divison by zero is not possible. 80.0 Divison by zero is not possible.
Explanation
In the python program above, @check_divisor
is actual use of decorator function which extends the behavior of function divide()
.
To understand how decorator function extends behavior of another function, lets consider how to write above code without using @check_divisor
:
def check_divisor(func):
def inner(a,b):
if b==0:
return "Divison by zero is not possible."
return func(a,b)
return inner
def divide(a,b):
return a/b
div = check_divisor(divide)
print(div(4,5))
print(div(40,0))
print(div(400,5))
print(div(23.4,0))
Output
0.8 Divison by zero is not possible. 80.0 Divison by zero is not possible.
Stepwise Analysis
- Here,
div = check_divisor(divide)
calls decorator functioncheck_divisor
which takes functiondivide
as an argument which meansfunc
will getdivide
. - But, remember function
check_divisor
returnsinner
function back to variablediv
. - Now when we call
div
likediv(a,b)
then it actually callsinner(a,b)
where it returns"Divison by zero is not possible"
ifb = 0
otherwise it returnsfunc(a,b)
so what isfunc
here? It isdivide
function, right? Look step 1 of step wise explanation. Soreturn func(a,b)
actually executesreturn a/b
from functiondivide(a,b)
.
Back to @check_divisor
Here, writing @check_divisor
before function definition of divide
is similar to:
divide = check_divisor(divide)
Real Life Scenario for Decorator
The real life example of decorator can be used in Django to disable the
unauthorized users from accessing the Django app. This can be done as
login_required()
decorator:
A default decorator has been made in django.contrib.auth.decorators
for
login required so,
from django.contrib.auth.decorators import login_required
@login_required
def protected_page(request):
……
login_required()
does the following:
- If the user isn’t logged in, redirect to
settings.LOGIN_URL
, passing the current absolute path in the query string. - If the user is logged in, execute the view normally.