In Python, decorators are a powerful feature that allow us to modify the behavior of a function or class without directly changing their source code. Decorators are implemented as functions, which take in another function as an argument and return a modified or enhanced version of the input function.
Decorators provide a clean and concise way to add additional functionality to existing functions, such as logging, input validation, caching, and more. They follow the concept of higher-order functions, where functions can be assigned to variables, passed as arguments, and returned as values.
Let’s dive into some examples to understand how decorators work and how they can be applied to functions.
Example 1: Basic Decorator
def decorator_function(original_function):
def wrapper_function():
print(f"Before calling {original_function.__name__}")
original_function()
print(f"After calling {original_function.__name__}")
return wrapper_function
@decorator_function
def say_hello():
print("Hello, world!")
# Calling the decorated function
say_hello()
Output:
Before calling say_hello
Hello, world!
After calling say_hello
In this example, we define a decorator decorator_function
that takes in a function as an argument. Inside the decorator, we define a wrapper_function
that adds some statements before and after calling the original function. Finally, we use the @decorator_function
syntax to apply the decorator to the say_hello
function.
Example 2: Decorator with Arguments
def prefix_decorator(prefix):
def decorator_function(original_function):
def wrapper_function(*args, **kwargs):
print(f"{prefix}: Before calling {original_function.__name__}")
result = original_function(*args, **kwargs)
print(f"{prefix}: After calling {original_function.__name__}")
return result
return wrapper_function
return decorator_function
@prefix_decorator("LOG")
def greet(name):
print(f"Hello, {name}!")
# Calling the decorated function
greet("Alice")
Output:
LOG: Before calling greet
Hello, Alice!
LOG: After calling greet
In this example, we extend the previous decorator to accept an additional argument prefix
. The decorator factory function prefix_decorator
returns the actual decorator function decorator_function
, which in turn returns the wrapper function wrapper_function
. This allows us to pass the prefix
argument and use it inside the decorator.
Conclusion
Decorators in Python provide a flexible and reusable way to modify the behavior of functions. They allow you to separate the core logic of a function from additional functionality that may vary or change over time. By applying decorators to your functions, you can enhance their capabilities without altering their original code, making your code more modular and maintainable.