Decorators are a powerful and advanced feature in Python that allows you to modify or enhance the behavior of functions or classes without changing their actual code. They are widely used in real-world applications, especially in frameworks like Flask, Django, and even in Python’s standard library.
In this lesson, we will cover:
- Understanding Function Decorators
- Creating and Using Decorators
1. Understanding Function Decorators
What is a Decorator?
A decorator is essentially a function that takes another function as an argument, adds some functionality to it, and returns the modified function. This is based on the concept of higher-order functions, which can accept other functions as arguments or return them.
Think of a decorator like adding toppings to a pizza. The base (original function) remains the same, but you can enhance it by adding extra ingredients (decorator).
Basic Syntax of a Decorator:
def wrapper_function():
print(“Wrapper executed before the original function.”)
original_function()
print(“Wrapper executed after the original function.”)
return wrapper_function
@decorator_function
def display():
print(“Hello from the original function!”)
display()
Explanation:
- decorator_functionis the decorator.
- original_functionis the function being decorated.
- The @decorator_functionsyntax is a shorthand for display = decorator_function(display).
- When display()is called, it’s actually invoking the wrapper_function, which adds functionality before and after the original display
2. Creating and Using Decorators
Creating a Simple Decorator:
Let’s create a decorator that logs the execution of functions:
def wrapper(*args, **kwargs):
print(f”Function ‘{func.__name__}’ is about to run.”)
result = func(*args, **kwargs)
print(f”Function ‘{func.__name__}’ has finished running.”)
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
print(add(5, 3))
Key Points:
- *argsand **kwargs are used to handle any number of positional and keyword arguments.
- The decorator logs messages before and after the function execution.
Decorators with Arguments:
Sometimes, you may want to pass arguments to your decorator. This requires an extra layer of functions:
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f”Hello, {name}!”)
greet(“Alice”)
Here, the greet function will be executed three times because of the @repeat(3) decorator.
Using Built-in Decorators:
Python provides several built-in decorators like:
- @staticmethod
- @classmethod
- @property
Example using @property:
def __init__(self, radius):
self._radius = radius
@property
def area(self):
return 3.14159 * self._radius ** 2
circle = Circle(5)
print(circle.area) # Accessing area like an attribute
When to Use Decorators?
- Logging: Track function calls and execution details.
- Authorization: Check user permissions before allowing access.
- Validation: Validate input data before processing.
- Caching: Store results of expensive function calls for faster future access.
✅ Summary:
- Decorators modify or enhance functions without changing their core code.
- They use higher-order functions to wrap additional functionality around the original function.
- Decorators can take arguments, handle function metadata, and even stack on top of each other.
In the next lesson, we’ll dive deeper into Generators, another powerful feature for efficient data processing in Python.
Leave a Reply