Explain Decorators in Python
In Python, decorators are a powerful and flexible way to modify or extend the behavior of functions or methods without directly altering their code. Decorators allow you to wrap another function and execute additional code before and/or after the wrapped function runs. They are often used to add functionality, perform pre/post-processing, or enforce certain behaviors.
Prerequisites for learning decorators
Before we learn about decorators, we need to understand a few important concepts related to Python functions. In Python, everything, including functions, is treated like an object. This means functions are objects too.
Let’s explore an example that demonstrates the calculation of a factorial using recursion.
Here’s a basic example to illustrate the concept of decorators:
Example
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
# Equivalent to: say_hello = my_decorator(say_hello)
say_hello()
Output
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
In this example, my_decorator is a function that takes another function (func) as its argument and returns a new function (wrapper). The wrapper function contains code that is executed before and after calling the original func. The @my_decorator syntax is a shorthand way of applying the decorator to the say_hello function. When say_hello() is called, it actually executes the wrapper function created by the decorator.
Decorating Functions with Parameters
Decorating functions with parameters involves modifying or enhancing the behavior of functions that accept arguments. When using decorators with parameterized functions, you need to account for the arguments passed to both the decorator and the decorated function.
Here’s an example to illustrate decorating a function with parameters:
Example
def my_decorator(prefix):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"{prefix}: Before function is called.")
result = func(*args, **kwargs)
print(f"{prefix}: After function is called.")
return result
return wrapper
return decorator
@my_decorator("INFO")
def greet(name):
print(f"Hello, {name}!")
# Equivalent to: greet = my_decorator("INFO")(greet)
greet("Alice")
Output
INFO: Before function is called.
Hello, Alice!
INFO: After function is called.
Summary
Decorators are widely used in Python, and they provide a clean and elegant way to extend or modify the behavior of functions without modifying their source code. This means you can add new features without repeating the same code. Decorators are useful for different things, such as: Authorization, Logging, Execution Time Measurement and Synchronization