Use of decorators in Python
In this article, we will learn about an important concept of functional programming. This is the use of Higher-Order Functions. In Python particularly, we implement this by the use of decorators. So, let’s dive deep into the world of decorators.
Decorators in Python
So, what do you mean by Higher-Order Function?
We refer any function to be a higher-order function if the function takes another function as one of its input arguments. Consider the following diagram:
If you look a the above diagram, you may feel that we are just passing the output of the function printName() to the input of the function Greet(). But, if you treat the functions as objects, then we can treat the above diagram as we are passing the function printName() as an input to another function Greet(). This is exactly the same concept as Higher-Order Functions. For example, consider the following code snippet:
def printName(name): print(name) def Greet(printName,name): msg = "Hi, " + name + " !" return printName(msg) # Original printName() function. printName("Arna") #Wrapped function. Greet(printName,"Arna")
The output of the above code snippet is as
Now, Let’s look at a slightly different approach to doing this:
name = "Arna" def printName(name): return name def Greet(f): def wrapper(name): return ("Hi, " + f(name) + " !") return wrapper # Original printName() function. print(printName("Arna")) # printName() modified with the Greet() function. printName = Greet(printName) # printName() after modification. print(printName("Arna"))
The above code snippet does the same thing as that of the previous snippet. But, in this case, the function Greet() behaves as a wrapper function to the input argument function printName(). The function Greet() therefore accepts printName() as an object, adds more features to it and again the newly created function is assigned with the name of printName.
In python, the function such as Greet() are, therefore, referred to as Decorators. Python also has a special syntax reserved for Decorators as shown below:
name = "Arna" def Greet(f): def wrapper(name): return ("Hi, " + f(name) + " !") return wrapper # printName() modified with the Greet() function. @Greet def printName(name): return name # printName() after modification. print(printName("Arna"))
The last two code snippets do the same thing, but the last one does the job in a cleaner and more elegant way.
So, in conclusion, we can say that decorators help us in adding more functionality to existing functions without affecting their interface with the rest of the program.