Python 3x Pandas Django

Decorators


Before you can understand decorators, you must first understand how Functions work.

Decorators to add functionality to an existing code(Functions\Methods)

It allows programmers to modify the behavior of existing function or class

Syntax

@decorator
def func_name():
    ''' Function implementation'''

is equivalent to

#Normal Function
def func_name():
    ''' Function implementation'''

func_name = decorated_function(func_name)

Basically, a decorator takes in a function, add\modify some functionality and returns it.

Code Snippet - Method 1

#decorator function
def make_pretty(func):
    def inner():
        print("I got decorated")
        func()
    return inner

#normal function
def ordinary():
    print("I am ordinary")

#decorator call
pretty = make_pretty(ordinary)
pretty()

Code Snippet - Method 2

#decorator function
def make_pretty(func):
    def inner():
        print("I got decorated")
        func()
    return inner

@make_pretty
def ordinary():
    print("I am ordinary")

#decorator call
ordinary()

Output - Method 1 & Method 2

I am ordinary
I got decorated
I am ordinary

In the both above methods make_pretty() is a decorator.

In the line pretty = make_pretty(ordinary), The function ordinary() got decorated and the returned function was given the name pretty and call the decorated function by pretty()

and we can see in the output, the decorator function added some new functionality to the original function. The decorator acts as a wrapper for the function ordinary.

So, @my_decorator is just an easier way of saying method 1. It’s how you apply a decorator to a function.

The syntax for decorators with parameters

@decorator(params)
def func_name():
    ''' Function implementation'''

is equivalent to

def func_name():
    ''' Function implementation'''

func_name = (decorator(params))(func_name)

Code Snippet

def smart_add_two_number(func):
    def inner(a, b):
        if type(a) == str or type(b) == str:
            print("OOPS!!! We can't add String Object")
            return

        return func(a, b)
    return inner
@smart_add_two_number
def add_two_number(a, b):
    print(a+b)

add_two_number(2,10)   #Output: 12
add_two_number(2,"K")  #Output: OOPS!!! We can't add String Object

You might notice that parameters of the nested inner() function inside the decorator is the same as the parameters of functions it decorates. Taking this into account, now we can make general decorators that work with any number of parameters.

In Python, this magic is done by *args & **kwargs. In this way, args will be the tuple of positional arguments and kwargs will be the dictionary of keyword arguments. An example of such a decorator will be:

def works_for_all_functions(func):
    def inner(*args, **kwargs):
        print("I can decorate any function")
        return func(*args, **kwargs)
    return inner

If you have any doubts or queries related to this chapter, get them clarified from our Python Team experts on ibmmainframer Community!