Once we have learned about closures which is an important part of the decorator learning process, we can move on to the functionality of a decorator. We must know that Python treats everything in it as objects, even a function is an instance of a specific object. Decorator is a method which allows you to wrap a function within a function using functions as attributes and calling it from within. A decorator literally represents its own name because it decorates a specific function to return a special value covered by an outer value, just like a gift.

In technical terms, it is simply used to modify the behaviour or callbacks of an existing function, it uses a function as an argument to the nested function, closure takes non-local parameters as an input, decorators take in entire functions as arguments to another function. Let’s learn about the necessities before:

First lets see an example of how we can manipulate a function object and assign it different names as an identifier.

def plus1(x): #A simple function to return a multiplier
   n = x * 5
   return n #returns n as the resultant value

print(plus1(5)) #simply prints a called function

newobj = plus1 #assigning a new object to the function instance

print(newobj(60)) #The new obj takes in values, the same as the original object.

Here we can see that we have assigned a new object to the original function object, which takes in value as normal, the newobj object is an identifier for the plus1 function object. Let’s see how we can pass a function and return from another function:

def p1(x): #A simple multiplier function
   return x * 2

def p2(x): #A simple division function
   return x / 2

def opr(func, x): #An operator function which imports a function along with a variable to be worked on!
   n = func(x) #Here it uses the x variable on whatever function we import to the opr function.
   return n

print(opr(p1,6)) #Here we used p1 in opr
print(opr(p2,6)) #Here we used p2 in opr as the division function

iden1 = opr #Here we used a different identifier to relate to the original function

print(iden1(p1,25)) #Calling the identifier with the multiplier function and a multiplying value.

Here we can see that we can call a function within a function even with multiple parameters to be used inside of the called function, it allows for greater flexibility and we will see how it contributes to a decorator later on!

A decorator, like it was discussed before, acts like a closure but in a way which can be termed as a double call, you can call the inner function with the non-local variable in the variable function but the original variable value is saved even though the variable value is changed during the second call. A modifying closure can also be called a decorator:

def stat1(func): #this is a closure

   def stat2(): #This inner function contains the actual "gift" of the decorator
       print("decorator")
       func() #The function is called, this will use the actual function we will provide to the new function object
   return stat2 #this returns the actual decorator function


def norm(): #this is the function which will be decorated
   print("the normal function or the gift ")


deco1 = stat1(norm) #Similar to a closure, we have defined a function object for the decorator
deco1() #Calling the decorator function

The above mentioned code is an example of a decorator without parameters, we can use multiple parameters along with the func parameter in the parent and normal functions.

def mul1(func):  #A simple closure with a function call as a parameter
   def mul2(a, b): #Child function that uses two separate parameters same as norm
       print("In this function will divide", a, "and", b)
       return func(a, b) #Returns the function on whom the decorator will be called

   return mul2 #returns the inner function just like a closure


@mul1  #The @ refers to a decorator by the name of mul1, using @ avoids the need of creating a special function object to call a decorator
def norm(a, b):
   n = a * b
   print(n)
norm(50,40) #A simple call on the normal function which will induce the decorator function.

Categorized in: