A decorator in Python is a design pattern that allows you to modify or enhance the behavior of functions or methods without changing their actual code. Decorators are a powerful tool for extending the functionality of existing code in a clean and maintainable way. They are often used to add functionality like logging, access control, memoization, and more.
1. Basic Syntax of a Decorator
In Python, a decorator is typically a function that takes another function as an argument, adds some functionality, and returns the original or modified function. The @
symbol is used to apply a decorator to a function.
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!")
say_hello()
The output will be:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
2. Function Decorators
Function decorators are commonly used to modify or enhance the behavior of functions. They are often used for tasks like logging, enforcing access control, instrumentation, and caching.
2.1. Example: Logging with a Decorator
Here’s an example of a simple logging decorator:
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling function {func.__name__}")
result = func(*args, **kwargs)
print(f"Function {func.__name__} finished executing")
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
result = add(5, 3)
print("Result:", result)
The output will be:
Calling function add
Function add finished executing
Result: 8
3. Passing Arguments to Decorators
Decorators can also accept arguments. This is done by defining a decorator that returns another decorator.
3.1. Example: Decorator with Arguments
Here’s an example of a decorator that repeats the execution of a function a specified number of times:
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 say_hello():
print("Hello!")
say_hello()
The output will be:
Hello!
Hello!
Hello!
4. Class Decorators
Decorators can also be applied to classes. A class decorator is a function that takes a class as an argument and returns a modified class.
4.1. Example: Class Decorator
def class_decorator(cls):
class Wrapped(cls):
def new_method(self):
print("New method added by decorator.")
def __str__(self):
return f"Instance of decorated {cls.__name__}"
return Wrapped
@class_decorator
class MyClass:
def __init__(self, value):
self.value = value
instance = MyClass(42)
print(instance)
instance.new_method()
The output will be:
Instance of decorated MyClass
New method added by decorator.
5. Built-in Decorators
Python also provides some built-in decorators, such as @staticmethod
, @classmethod
, and @property
.
5.1. Example: @staticmethod
and @classmethod
class MyClass:
@staticmethod
def static_method():
print("This is a static method.")
@classmethod
def class_method(cls):
print("This is a class method.")
MyClass.static_method()
MyClass.class_method()
The output will be:
This is a static method.
This is a class method.
6. Practical Uses of Decorators
Decorators are widely used in various real-world scenarios:
- Logging: Automatically log function calls and results.
- Access Control: Check user permissions before executing a function.
- Memoization: Cache the results of expensive function calls.
- Validation: Validate input arguments before passing them to the function.