Decorators to add new functionality to the existing code. Basically a decorator takes in a function, add functionality and return it.
Before understanding Decorators, we need to get some knowledge on Nested functions, Non-local variables and closures.
Nested Functions: A function is defined inside a function is called Nested function.
Program:
def outer_function():
# This is a outer function
def inner_function():
# This is a inner function
print("This is Inner Function")
inner_function()
# inner function called
outer_function()
# outer function called
Output:
This is a Inner Function
Non-local Variables: Nested functions (Inner function) can access variables of enclosing scope (Outer Function)
Program:
def outer_function(message):
# This is a outer function
def inner_function():
# Accessing outer function variable
print(message)
# This is a inner function
print("This is Inner Function")
inner_function()
# inner function called
outer_function("Hello,")
# outer function called
Output:
Hello,
This is Inner Function
Closures: Closure is a function object that remembers values (inner function) in the enclosing scopes (outer function)
Program:
- def calculate_squares(exponent):
- def squares(base):
- return pow(base, exponent)
- return squares # In closures we need to return the function without parenthesis
- square = calculate_squares(2)
- print(square(2))
- print(square(3))
Output:
4
9
Will try to understand the above program. We called calculate_squares(2) in line6 and it returned a function squares in line4. The returned function squares bound to the name square in line6. In simple terms squares function is stored in square variable with calculate_squares function value 2 (non-local variable).
In line7 and 8, we are calling square(2) and square(3) that means square variable having inner function squares() with values of outer function calculate_squares. Here the value is exponent = 2 which is non local variable.
Decorators: As mentioned above decorator takes in a function, add functionality and return it.
Program:
- def decorator_func(func):
- def wrapper_func():
- print("Hi")
- func()
- return wrapper_func
- def greeting_func():
- print("How are you")
- hi = decorator_func(greeting_func)
- hi()
Output:
Hi
How are you
Will try to understand above program, greeting_func() function only prints "How are you", we feel the greeting is incomplete, we want to add "Hi" before "How are you", we need add some functionality to greeting_func() function to complete our requirement.
As mentioned in the definition decorator takes in a function and adds functionality and return it. So in line10 decorator_func() takes greeting_func() as input. So before calling the greeting_func() we added a print statement in line3. So we got the above ouput. Here we didn't touch greeting_func() but we added some functionality to it.
The above program is equivalent to the below program.
Program:
- def decorator_func(func):
- def wrapper_func():
- print("Hi")
- func()
- return wrapper_func
- @decorator_func # This line is equivalent to the lines 10 and 11 in the above program
- def greeting_func():
- print("How are you")
- greeting_func()
Sample Program: 1
def decorator_func(func):
def wrapper_func(x,y):
print("division between", x,"and", y)
if y == 0:
print("Divisible by zero is not possible")
return
return x/y
return wrapper_func
@decorator_func
def division(x,y):
return x/y
print(division(10,2))
print(division(10,5))
print(division(10,0))
output:
division between 10 and 2
5.0
division between 10 and 5
2.0
division between 10 and 0
Divisible by zero is not possible
None