Python Decorators
A decorator is an advanced feature in Python used todynamically extend the functionality of functions or classes without modifying the original function code。
Essentially, a decorator is a function: it receives a function as an argument and returns a new function (usually an enhanced version of the original function).
Decorators are applied using the@decorator_namesyntax placed before a function or method definition.
Python also provides some built-in decorators, such as@staticmethodand@classmethod。
Common use cases:
- Logging:Record function call information, parameters, and return values
- Performance statistics:Measure function execution time
- Access control:Restrict function access permissions
- Caching:Cache function results to improve performance
Basic Syntax
The core idea of a decorator is:using one function to "wrap" another function。
Syntax
def wrapper(*args, **kwargs):
# Before calling
print("Before execution")
result = original_function(*args, **kwargs)
# After calling
print("After execution")
return result
return wrapper
@decorator_function
def target_function():
print("Original function execution")
Explanation:
decorator_function: decorator function (receives the original function)wrapper: wrapper function (actually executed)@decorator_function: equivalent to function replacement
Equivalent form:
target_function = decorator_function(target_function)
👉 When callingtarget_function(), what is actually executed iswrapper()
Using Decorators
Decorators are applied using the@syntactic sugar placed before the function definition:
@time_logger
def target_function():
pass
Equivalent to:
def target_function():
pass
target_function = time_logger(target_function)
This mechanism allows us to uniformly add functionality (such as logging, permissions, etc.) without modifying the original function.
Example: Printing Logs
def wrapper():
print("Before function execution")
func()
print("After function execution")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
Output:
函数执行前 Hello! 函数执行后
my_decoratorReceivessay_hello@my_decoratorReplaces the original function
Decorators with Parameters
If the original function has parameters, you need to, in thewrapperuse*args, **kwargs:
Example
def wrapper(*args, **kwargs):
print("Before execution")
func(*args, **kwargs)
print("After execution")
return wrapper
@my_decorator
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
Output:
执行前 Hello, Alice! 执行后
Explanation:Using*args, **kwargscan accommodate functions with any number of parameters.
Decorators with Parameters (Advanced)
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def say_hello():
print("Hello!")
say_hello()
Explanation:This is a "decorator factory"; the outer function is used to receive parameters.
Hello! Hello! Hello!
Class Decorators
In addition to functions, decorators can also be applied to classes.
A class decorator receives a class and returns a modified class or a wrapper class.
- Enhance class methods
- Control the instantiation process
- Implement functionality such as singletons and logging
Function-based Class Decorators
Example
class Wrapper:
def __init__(self, *args, **kwargs):
self.wrapped = cls(*args, **kwargs)
def __getattr__(self, name):
return getattr(self.wrapped, name)
def display(self):
print("Before call")
self.wrapped.display()
print("After call")
return Wrapper
@log_class
class MyClass:
def display(self):
print("Original method")
obj = MyClass()
obj.display()
Before call Original method After call
Class-based Class Decorators
Example: Singleton Pattern
def __init__(self, cls):
self.cls = cls
self.instance = None
def __call__(self, *args, **kwargs):
if self.instance is None:
self.instance = self.cls(*args, **kwargs)
return self.instance
@SingletonDecorator
class Database:
def __init__(self):
print("Initialization")
db1 = Database()
db2 = Database()
print(db1 is db2)
初始化 True
Built-in Decorators
Commonly used built-in decorators:
- @staticmethod: defines a static method
- @classmethod: defines a class method
- @property: turns a method into a property
Example
@staticmethod
def static_method():
print("Static method")
@classmethod
def class_method(cls):
print(cls.__name__)
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
Stacking Multiple Decorators
Multiple decoratorswrap the function from bottom to top during the definition phase,and execute from top to bottom during the calling phase:
Example
def wrapper():
print("Decorator 1")
func()
return wrapper
def decorator2(func):
def wrapper():
print("Decorator 2")
func()
return wrapper
@decorator1
@decorator2
def say_hello():
print("Hello!")
say_hello()
Final output:
Decorator 1 Decorator 2 Hello!
Core Summary
Decorator = a function that wraps a function + extending functionality without modifying the original code
- The @ syntax is essentially function replacement
- wrapper is the function that is actually executed
- It is recommended to use *args, **kwargs for greater versatility
- Supports functions, classes, and even decorators with parameters