Suppose, you have a function and you want to change its behavior without changing its code. How do you do that? Yes, you need to use decorators!

Before, discussion about decorators let’s have a brief discussion about function.

Function is a named block of code which performs a specific task (yes “a specific task”, if a function performs more than one task then the function should be split into multiple functions. It may differ depending on situation, it’s just a trade-off!).

Here, we have declared a function named describe_myself which prints the value of given argument (name) .

In Python, functions are first-class object (first class citizen too!). Read about first-class object here.

Higher-order Function

Functions in python can be higher-order. When a function takes a function as argument and/or returns a function then it’s called higher order function.

Here, our_higher_order_function takes another function as argument and calls the function.

Inner Function

A function can be inside another function. It’s called inner function. Inner functions are scoped inside its parent function.

We are creating and calling child function inside parent function. child functions are not directly accessible outside of parent function. If we want to call our_child_function from outside of our_parent_function then we shall get an error :

But, here is a interesting trick! As in Python, a function can return another function then we can take it’s benefit.

Here, we are returning the reference of our_child_function , storing in child_function and calling it. Interesting, No?

Our first decorator

Let, we want to print our country’s name along with our name but we won’t change our describe_myself function.

Here, our_first_decorator takes func as argument , modifies its behavior and returns a new function. We are assigning the modified functions reference to describe_myself variable and calling through it.

Yes, this is our first decorator! A decorator wraps a function by modifying its behavior. We’ve done the same thing in the previous code.

Polish our first decorator

Using our_first_decorator is not looking awesome yet. We can use it in smarter way by using @ symbol (sometimes, @ is called pie-decorator) .

The following block of code will do the same as previous one.

Here we’ve hard coded “Bangladesh” in our wrapper function. We can pass arguments for the wrapper too!

It looks nicer now!

Introspection our decorator

Let’s introspect our function and decorator:

Wait, for print(describe_myself.__name__) it shows that name of describe_myself function is wrapper ! Shouldn’t it be describe_myself ?

However, after being decorated, describe_myself has gotten confused about its identity. It reports of being the wrapper inner function of our_first_decorator . Though this information is technically not wrong but not very useful information.

We can solve this issue by using @functools.wraps decorator. A custom decorator should use this decorator to preserve its information.

It looks fine now!

In this brief discussion, we have completed some basics of python decorator and developed our first python decorator! :)

You can also read :