Python Decorator: A Decorator is an interesting feature of Python that helps the user design patterns and insert a new functionality to an existing object without making any modifications in its structure. Usually, we call Decorators before defining the function that we want to decorate. We will discuss a lot about the decorators and their uses in Python Programming. Moreover, this type programming is also known as metaprogramming because, in this programming, one part of the program is modified by another during the compilation time and vice versa.
The functions in Python are First-Class Object, which means they support various operations. For example – Being returned from a function passed as an argument, modified, assigned to a variable and many more. Let’s start exploring how to implement decorators in the Python Programs and many in the following sections.
Before we jump into Python decorators’ depth, there are some fundamentals we must need to know.
Starting with the fact that everything in Python (Even the classes) are objects. The Names that we define works as identifiers that are bounded to these objects. There are no exceptions that even Functions are also objects (with attributes). We can bound different names to the same function object. The same is illustrated in the following example.
Example –
The above snippet of code should produce an Output, as shown below:
Output:
As we can observe, we are getting the same result from both the functions, initial and final, respectively. And the name initial and final refers to the same function object.
Now, let’s explore a bit deeper into this section. We can also pass one function to another as an argument. This functionality can be seen in various functions such as filter, map and reduce in Python. Such functions are also known as higher-order functions as these functions take other functions as arguments. The same is demonstrated in the following example:
The above function can be invoked using a python interpreter, as shown below:
Output:


In the above example, we can observe that a nested function, namely isreturned(), is defined and return each time we call iscalled().
First of all, the methods and functions are Callable because of their ability to be called. Any object can be termed as callable if it implements the special method called __call__(). Thus, we can say that a decorator is also a callable that helps return a callable.
More specifically, a decorator takes a function as input, adds some functionality to it and returns it. We can see the following example for more understanding.
Output:
This is an ordinary function.
Output:
This function is decorated!!
In the above example, we have to use the function pretty() as a decorator. In the assignment step:
We have decorated the function the_ordinary() function and give the name the_pretty() to the returned function.
As we can observe that the original function is decorated using the decorator function that added some new functionality to it. This is kind of similar to gift packaging. The decorator works as a wrapper. It does not alter the nature of the object that got decorated, i.e., the real gift inside. However, the present looks pretty now (since it got decorated).
Usually, a function is decorated and reassigned as follows:
The syntax shown above is a common construct and can be easily simplified in Python.
This can be done using the @ symbol alongside the decorator function name and placing it above the function definition that is to be decorated. Let’s see the following example:
is equivalent to
The above example is simply a cube of syntactic sugar for implementing Python decorators.
The decorator shown above was quite simple and usually worked with functions with no parameters. But how to decorate the functions that take in parameters such as:
The above function has two parameters, x and y. And we know that it will return an error if we pass in y as 0.
Now, we will be making a decorator for checking for this case that will cause the error.
Let’s try the above snippet of code and see the output we get:
As we can observe, the decorator function implementation will return none whenever the error persists. And Thus, we can decorate the functions with parameters.
We can chain multiple decorators in Python. This statement implies that we can decorate a function multiple times with the same or different decorators. All we need is to place the decorator above the chosen function. Here’s an example is shown below:
The above snippet of code should produce an Output, as shown below:
The above syntax of
is equivalent to


In addition to the above, one more factor affects the decorators’ chaining. This factor is the order of chaining the decorators. If we had reversed the order as
The Output would be:

source