Decorators
Decorators in Python are a powerful and flexible tool that allow you to modify the behavior of functions or methods without changing their actual code. They are often used to add functionality such as logging, access control, memoization, or instrumentation to existing functions in a clean, readable, and reusable way.
Basic Syntax
A decorator is a function that wraps another function. The basic syntax is:
def decorator_function(original_function):
def wrapper_function(*args, **kwargs):
# Code before the function call
result = original_function(*args, **kwargs)
# Code after the function call
return result
return wrapper_function
original_function
: The function being decorated.wrapper_function
: The function that wraps around the original function, adding additional behavior before and after it.
Applying a Decorator
You can apply a decorator to a function using the @
symbol before the function definition.
- Example:
def my_decorator(func): def wrapper(): print("Something before the function.") func() print("Something after the function.") return wrapper @my_decorator def say_hello(): print("Hello!") say_hello() # Output: # Something before the function. # Hello! # Something after the function.
Decorators with Arguments
Decorators can also accept arguments, allowing you to customize their behavior.
- Example:
def repeat(num_times): def decorator_repeat(func): def wrapper(*args, **kwargs): for _ in range(num_times): result = func(*args, **kwargs) return result return wrapper return decorator_repeat @repeat(num_times=3) def greet(name): print(f"Hello, {name}!") greet("Alice") # Output: # Hello, Alice! # Hello, Alice! # Hello, Alice!
Common Use Cases
-
Logging:
- Automatically log information about function calls.
def log_function_call(func): def wrapper(*args, **kwargs): print(f"Calling {func.__name__} with {args} and {kwargs}") return func(*args, **kwargs) return wrapper @log_function_call def add(x, y): return x + y result = add(3, 5) # Output: Calling add with (3, 5) and {}
-
Access Control/Authentication:
- Control access to certain functions based on user permissions.
def require_permission(permission): def decorator(func): def wrapper(*args, **kwargs): if not user_has_permission(permission): raise PermissionError(f"User lacks {permission} permission") return func(*args, **kwargs) return wrapper return decorator @require_permission("admin") def delete_user(user_id): print(f"User {user_id} deleted.")
-
Memoization:
- Cache the results of expensive function calls to improve performance.
def memoize(func): cache = {} def wrapper(*args): if args not in cache: cache[args] = func(*args) return cache[args] return wrapper @memoize def fibonacci(n): if n in [0, 1