We have covered Lambda functions in the Python tutorial; now, let's understand Decorators. Grasping this concept all at once might be a bit challenging, but it will become easier with practice.
What are Decorators in Python programming?
Decorators are essentially functions, they take another function as input and return a modified version of that function.
In other worlds, Decorators are one of the most powerful features of the Python language. They allow coders to modify or extend the behavior of a function without altering its source code.
Example:
def decorator ( func):
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
@decorator
def greet_me()
print("Hello")
greet()
@decorator meansgreet_me = decorator(greet_me)
We can also write without @decorators
def decorator ( func):
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
def greet_me()
print("Hello")
greet_me = decorator(greet_me)
greet()
Note:
- func is the argument function, i.e., the original function you pass into the decorator.
- You should not change or modify func itself directly inside the decorator.
- Instead, you call it inside the wrapper whenever you want it to execute.
Why need Decorators?
Suppose we have multiple functions, and whenever we execute one of them, a specific function should also run. In such a scenario, we can use a decorator to automatically execute that required function for tasks like logging, permission checks, timing, etc. whenever the other functions are called.
Example: Without Decorators
def add_user():
print("You are logged in")
print("Add user")
def update_user():
print("You are logged in")
print("Update user")
def delete_user():
print("You are logged in")
print("Delete user")
You can check that [print ("You are logged in")] execute every time. With the decorators, we can solve this challege.
Decorators with Function arguments
Wrapper function also accepts the argument.
def what_is(func):
def wrapper(name):
print("Type your name")
func(name)
print("Thanks for contacting")
return wrapper
@what_is
def naming(name):
print(f"My name is, {name}")
naming("Somit Vishwakarma")*args and **kwargs
*args and **kwargs so the decorator can work with different functions regardless of their parameters.*args collects all extra positional arguments into a tuple, and **kwargs collects all extra keyword arguments into a dictionary. The values inside them can be of any type, such as lists, numbers, strings, or objects.def decorator(func):
def wrapper(*args, **kwargs):
print("Before execution")
result = func(*args, **kwargs)
print("After execution")
return result
return wrapper
Small project: Execution Time
import time
def execution_time(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"execution time = {start - end:.4f} seconds")
return result
return wrapper
@execution_time
def run()
time.sleep(2)
run()Multiple Decorator Use
def decorator1(func):
def wrapper():
print("1st decorators")
func()
return wrapper
def decorator2(func):
def wrapper():
print("2nd decorators")
func()
return wrapper
@decorator1
@decorator2
def show()
print("hello")
show()Function Metadata
When you create a decorator in Python, the decorator usually replaces the original function with a wrapper function. This can cause the original function's metadata (such as its name, docstring, annotations, and module information) to be lost.
functools.wraps solves this problem by copying metadata from the original function to the wrapper.def decorator ( func):
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
@decorator
def welcome()
'''Return Doc String'''
print("Hello")
print(welcome.__name__)
print(welcome.__doc__)from functools import wraps
def decorator ( func):
@wraps(func)
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
@decorator
def welcome()
'''Return Doc String'''
print("Hello")
print(greet.__name__)
print(greet.__doc__)
Note: without functools wraps; the function is run normally. It is only used to return the original metadata.
Tasks:
1. Create a decorator that prints:
Starting...
