How to make chain of function decorators in Python

In this tutorial, we are going to see how to make a chain of function decorators in Python. Firstly we should know about the properties of functions in Python. Functions act like objects in Python. Many of you wonder, what is there in the Python functions. Let’s see it.

In Python, Functions can be

  • defined within other function.
  • passed as arguments to other functions.
  • returned by other functions.

What is a decorator?

A decorator is like adding additional functions to existing functions. Those additional functions will also be defined but we don’t call those additional functions like function() instead we use them as a decorator to the basic function. To know more about decorators and its usage read this Use of decorators in Python.

Chaining decorators in Python

We can use many decorators to a single function. Say, A function may have more than one decorator while invoking it. In the following Code, We will be using two decorators to the calling function.

def inner1(func):
    def inside_inner1(msg):
        print('*'*5,end='')
        print("invoked inner1 function"+('*'*5))
        func(msg)
    return inside_inner1
def inner0(func):
    def inside_inner0(msg):
        print('%'*5,end='')
        print("invoked inner0 function"+('%'*5))
        func(msg)
    return inside_inner0
@inner0
@inner1
def inner2_called(msg):
    print(msg)
msg="this is 2nd inner function but called first"
inner2_called(msg)

This code will give the output as:

%%%%%invoked inner0 function%%%%%
*****invoked inner1 function*****
this is 2nd inner function but called first

You can see that we are calling only inner2_called() functions but by adding two decorators before it. It implements the additional functionality and it executes the called function.

The above snippet

@inner0
@inner1
def inner2_called(msg):
    print(msg)

is equivalent to

def inner2_called(msg):
    print(msg)
inner0(inner1(inner2_called))

If the decorator’s order changed, then the code executes accordingly. let us assume it interchanged.

def inner1(func):
    def inside_inner1(msg):
        print('*'*5,end='')
        print("invoked inner1 function"+('*'*5))
        func(msg)
    return inside_inner1
def inner0(func):
    def inside_inner0(msg):
        print('%'*5,end='')
        print("invoked inner0 function"+('%'*5))
        func(msg)
    return inside_inner0
@inner1
@inner0
def inner2_called(msg):
    print(msg)
msg="this is 2nd inner function but called first"
inner2_called(msg)

The output will be

*****invoked inner1 function*****
%%%%%invoked inner0 function%%%%%
this is 2nd inner function but called first

This acts like inner1(inner0(inner2_called)). Hope you understand.

Leave a Reply