Introduction

Before looking into Decorators, we need to know key points about Functions in Python.

  • Functions are Objects. Means they can be referenced, passed as an argument, can be returned as well.

Decorators dynamically alter the functionality of a function, method, or class without having to directly use subclasses or change the source code of the function being decorated

Implementaion

Function as a Decorator

Boilerplate Code:

import functools

def decorator(func):
    @functools.wraps(func)
    def wrapper_decorator(*args, **kwargs):
        # Do something before
        value = func(*args, **kwargs)
        # Do something after
        return value
    return wrapper_decorator

Now we will see an example, how much time it took for a function to execute.

There are two ways to call a decorator (Both ways are shown in the code below):

  1. By using @ symbol.
  2. By wrapping the decorator on to a function.

Class as a Decorator

Recall in the 2nd method above we have called the decorator using test2 = timer(test2). If timer is a class, it needs to take func as an argument in its __init__() method. The logic has to be written in __call__() method.

Boilerplate Code:

class Decorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        # Do something before
        result = self.func(*args, **kwargs)
        # Do something after
        return result

Now we will see the same example as above using Class Decorator

Decorators with Arguments

We can pass some arguments to the Decorator as well. For that we have to enclose the whole decorator boilerplate code inside another function.

In the example we will send num_times to decorator and the decorator will call the wrapper function that many times.

Multiple Decorators on a function

We can call multiple decorators on a single function.

Note: Order of the decorators is IMPORTANT.

In the below example @repeat will be called first and @timer later. If we reverse the order the execution of the decorator is reversed. We are using the same repeat and timer decorators define in above examples.