Python decorators

A decorator is a special function that added a feature to an existing function without changing its calling signature.

Understanding functions

You can have a function with another function inside it. You can return single value, multiple value or even a function. Let’s see an example

def add(a, b):
    # returns single value
    return a + b


print(add(3, 4))


def multiple_return(a, b):
    # returns multiple value making it tuple
    return a, b


print(multiple_return(33, 44))


def outer_function():
    # returning another inner function
    print('Inside outer function')

    def inner_function():
        print('Inside inner function')

    return inner_function


x = outer_function()
# To print inner function call x()
x()

Output:

7
(33, 44)
Inside outer function
Inside inner function

Understanding Decorator:

Decorator are special method which return another method after adding some feature to it. Let’s create a simple example

def decorator_function(func):
    def inner_function():
        print('decorated by decorator_function')
        func()

    return inner_function


def display_flower():
    print('Display flower')


decorate_flower = decorator_function(display_flower)
decorate_flower()

Output:

decorated by decorator_function
Display flower

This style of programming by returning a function rather than a value is common practice in python programming. Therefore python has a syntactic sugar to this style or equivalent way to this style. The @method_name technique is use to perform same task. Let’s see an equivalent implementation of above functions.

def decorator_function(func):
    def inner_function():
        print('decorated by decorator_function')
        func()

    return inner_function


@decorator_function
def display_flower():
    print('Display flower')


# call the function directly
display_flower()

Output:

decorated by decorator_function
Display flower

As you can see using @decorator_function to implemented method decorates it and makes it’s call pass through decorator function.

Passing parameters to decorator:

decorators can also take parameters. Let’s divide a number and decorate it to check if second number is zero or not. 

def decorate_division(func):
    def inner(a, b):
        print(' dividing two numbers : ', (a, b))
        if b == 0:
            print("Can't divide by zero")
            return
        print('division okay')
        return func(a, b)

    return inner

@decorate_division
def division(a, b):
    return a / b

a = division(8, 4)
print('a=', a)
b = division(5, 0)
print('b=', b)

Output:

 dividing two numbers :  (8, 4)
division okay
a= 2.0
 dividing two numbers :  (5, 0)
Can't divide by zero
b= None

Using multiple decorators

You can apply multiple decorator in python. Let’s see an example

def square_of_number(func):
    def inner(x):
        print('Inside square of number')
        r = x ** 2
        print("Square of ", x, " = ", r)
        func(x)

    return inner


def sum_numbers(func):
    print('Inside sum_numbers')

    def inner_function(list_item):
        result = sum(list_item)
        func(result)

    return inner_function


@sum_numbers
@square_of_number
def square_of_sum_of_list(list1):
    print('Inside square_of_sum_of_list ')


square_of_sum_of_list([1, 2, 3])

Output:

Inside sum_numbers
Inside square of number
Square of  6  =  36
Inside square_of_sum_of_list 

As you can see the first decorator on top i.e.  @sum_numbers is executed first and then the second decorator @square_of_number and then only the actual function i.e. square_of_sum_of_list(). These kinds of decorators are common when python is used for web development applications for authenticated users only if they are logged in. 

Leave a Reply

Your email address will not be published. Required fields are marked *