Decorators in python
HIGHER ORDER FUNCTIONS: In mathematics and computer science, a higher-order function is a function that does at least one of the following:
- takes one or more functions as arguments (i.e. procedural parameters),
- returns a function as its result.
def sayhello(name): #regular functions
return ('hello ' + name)
def sayhi(name): #regular functions
return ('hi ' + name)
def greet(function_name): #higher order-order function
return function_name("James")
greet(sayhello)
greet(sayhi)
Output:
hello James
Hi James
As you can see there are two regular functions defined as sayhello( ),
Inner Functions:
In python, we can define functions under functions. To illustrate this let take an example:
def outer():
print("Printing from the outer() function")
def first_inner():
print("Printing from the first_inner() function")
def second_inner():
print("Printing from the second_inner() function")
second_inner()
first_inner()
outer()
Output:
Printing from the outer() function
Printing from the second_inner() function
Printing from the first_inner() function
As we can see from the above code inner functions have been defined inside
Let us try above concepts in below code:
def outer(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
def say_hello():
print("Hello!")
x = outer(say_hello)
x()
Output:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
We first give the x a function object pointing to the wrapper function( why? because the outer function returns wrapper function object). When we call the function x() then it being a wrapper function object calls wrapper function which prints out – “Something is happening before the function is called.” After that, as we’ve passed a say_hello function object to the outer function, hence it can be called now without giving any error. And finally, “Something is happening after the function is called.” is printed.
What is happening here can be explained below with the definition of Decorators.
A decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it.
Now the line “x = outer(say_hello) ” can be written in a more “decorative” way like this –
def outer(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@outer ## that is our decorator ##
def say_hello():
print("Hello!")
say_hello()
Output:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
What if the function say_hello() had one or more arguments?
def outer(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@outer
def say_hello(name):
print("Hello! "+name)
say_hello("Shiva")
Output:
Traceback (most recent call last):
File "/home/shivam/.PyCharmCE2018.2/config/scratches/scratch.py", line 1300, in <module>
say_hello("Shiva")
TypeError: wrapper() takes 0 positional arguments but 1 was given
Process finished with exit code 1
To make it work we will use:
- *args (Non Keyword Arguments)
- **kwargs (Keyword Arguments)
Since func function under wrapper function expects arguments we have to provide it with them in this way. Look at the correct code:
def outer(func):
def wrapper(*args,**kwargs):
print("Something is happening before the function is called.")
func(*args,**kwargs)
print("Something is happening after the function is called.")
return wrapper
@outer
def say_hello(name):
print("Hello! "+name)
say_hello("Shiva")
Output:
Something is happening before the function is called.
Hello! Shiva
Something is happening after the function is called.