1. What is a Decorator?
A decorator in Python is a higher-order function that modifies the behavior of another function without changing its code. Decorators allow code reusability, logging, access control, and more.
Key Features of Decorators:
✅ Wraps a function to extend its behavior
✅ Uses @decorator_name
syntax
✅ Functions are treated as first-class objects in Python
2. Basic Function Decorator
A decorator is a function that takes another function as input, modifies it, and returns a new function.
2.1 Simple Decorator Example
def my_decorator(func):
def wrapper():
print("Before function execution")
func()
print("After function execution")
return wrapper
@my_decorator # Applying the decorator
def say_hello():
print("Hello, World!")
say_hello()
Output:
Before function execution
Hello, World!
After function execution
3. Using functools.wraps
When using decorators, function metadata (__name__
, __doc__
) may be lost. To preserve metadata, use functools.wraps
:
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("Before function execution")
result = func(*args, **kwargs)
print("After function execution")
return result
return wrapper
@my_decorator
def greet(name):
"""Greet a person by name."""
print(f"Hello, {name}!")
print(greet.__name__) # Output: greet
print(greet.__doc__) # Output: Greet a person by name.
4. Decorators with Arguments
A decorator can accept arguments by wrapping it inside another function:
import functools
def repeat(n):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3) # Executes function 3 times
def say_hi():
print("Hi!")
say_hi()
Output:
CopyEditHi!
Hi!
Hi!
5. Decorating Functions with Arguments
If a function has parameters, the decorator must accept *args
and **kwargs
:
def uppercase_decorator(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
@uppercase_decorator
def greet(name):
return f"Hello, {name}"
print(greet("Alice")) # Output: HELLO, ALICE
6. Applying Multiple Decorators
You can stack multiple decorators:
def bold(func):
def wrapper():
return f"<b>{func()}</b>"
return wrapper
def italic(func):
def wrapper():
return f"<i>{func()}</i>"
return wrapper
@bold
@italic
def text():
return "Hello"
print(text()) # Output: <b><i>Hello</i></b>
Order matters: The closest decorator to the function runs first.
7. Class-Based Decorators
You can define decorators using classes with __call__
method:
class LogDecorator:
def __call__(self, func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with arguments {args} {kwargs}")
return func(*args, **kwargs)
return wrapper
@LogDecorator()
def add(a, b):
return a + b
print(add(2, 3)) # Output: Calling add with arguments (2, 3) {} -> 5
8. Common Use Cases of Decorators
Use Case | Example |
---|---|
Logging | @log_decorator to track function calls |
Authentication | @auth_required to restrict access |
Memoization (Caching) | @functools.lru_cache for caching |
Timing Execution | @time_it to measure execution time |
Input Validation | @validate_input to check arguments |
9. Built-in Python Decorators
Python provides built-in decorators:
Decorator | Purpose |
---|---|
@staticmethod | Defines a static method inside a class |
@classmethod | Defines a class method |
@property | Defines a getter method |
@functools.lru_cache | Caches function results |