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

  1. Here, div = check_divisor(divide) calls decorator function check_divisor which takes function divide as an argument which means func will get divide.
  2. But, remember function check_divisor returns inner function back to variable div.
  3. Now when we call div like div(a,b) then it actually calls inner(a,b) where it returns "Divison by zero is not possible" if b = 0 otherwise it returns func(a,b) so what is func here? It is divide function, right? Look step 1 of step wise explanation. So return func(a,b) actually executes return a/b from function divide(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:

  1. If the user isn’t logged in, redirect to settings.LOGIN_URL, passing the current absolute path in the query string.
  2. If the user is logged in, execute the view normally.