/    /  Python – Decorators

Python Decorators

So far, we have covered various aspects of OOPS concepts in relevance to Python, but we have observed a unique behavior here as everything we have discussed is dependent on underlying principles of Class and Object.

Being Said that everything we create is a class and its children variables and functions describe the behavior of the Class. Functions define the logic that the Class carries upon, Objects hide the function logic through Constructors.

So now we are well versed about what Functions are how to create them how to access them within the class and outside the class.

Whatever we create in python are referred to as objects which include Functions as well. Functions are Objects with attributes passed as parameters.

Functions do follow the principle of polymorphism as a function exists in multiple forms they can be accessed through different names as instances.


Let us understand it through below example:

def test(x):
	print(x)
test(“abc”)
real = test
real(“abc”)


When we run the above code, real and test gives same output as abc. Here real and test do refer to same function object which has x as attribute.


Output:

Functions are always callable as they can be called from anywhere within the class. Ideally in OOPS, any object that can be called is termed to be as Callable Object, Functions are not exception to them either.

Here comes the concept of Decorators as the name suggests Decorators add some kind of Decorative Behaviour to the function.

Decorators are similar to functions, but they do refer to as metafunctions as they does not alter any logic to existing function only difference is they add some functionality and return them.


Let us understand Decorators through an example:

def decorate(fun):
    def f1():
        print("I am Decorated through Decorator")
        fun ()
    return f1
def norm():
    print("I am Normal Function")


Executing above Code, gives us the response as:


In order to convert the norm() function as decorator function, let us add some logic to it as


In the above logic decorate() is playing the role of Decorator. Initially when norm() function was called, it returned the response as Normal Function, but when we have called decorate(norm) function as decorating norm function through Decorator, norm function got Decorated.

Similarly, we can call Decorator function through Annotation(@).

We need to place the @ symbol along with Decorator function name above the function definition which needs to be decorated.


Let us see how to perform this as:

@decorate
def norm():
	print(“ I am Normal Function”)

which is similar to

def norm():
	print(“I am Normal Function”)
norm = decorate(norm)


Output:


Similar to Nested Functions, we can have Nested Decorators which are also referred to as Chaining Decorators.

def star(f):
    def i(*args, **kwargs):
        print("*" * 5)
        f (*args, **kwargs)
        print("*" * 5)
    return i
def percent(f):
    def i(*args, **kwargs):
        print("%" * 5)
        f(*args, **kwargs)
        print("%" * 5)
    return i
@star # Calling Star Decorator
@percent # Calling Percent Decorator
def prin(msg):
    print(msg)
prin("Python")


Output: