Python Decorators
## Python3.x Python Decorators
Decorator (decorator) is an advanced feature in Python used to **dynamically extend the functionality of a function or class without modifying the original function's code**.
Essentially, a decorator is a function: it takes a function as a parameter and returns a new function (usually an enhanced version of the original function).
!(#)
Decorators are applied to function or method definitions using the @decorator_name syntax.
Python also provides some built-in decorators, such as @staticmethod and @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: **"wrapping" another function with a function**.
## Syntax
def decorator_function(original_function):
def wrapper(*args, **kwargs):
# Before call
print("Before execution")
result = original_function(*args, **kwargs)
# After call
print("After execution")
return result
return wrapper
@decorator_function
def target_function():
print("Original function execution")
**Analysis:**
* `decorator_function`: The decorator function (receives the original function)
* `wrapper`: The wrapper function (actually executed)
* `@decorator_function`: Equivalent to function replacement
**Equivalentapproach:**
target_function = decorator_function(target_function)
? When calling `target_function()`, it actually executes `wrapper()`
* * *
### Using Decorators
Decorators are applied to function definitions using the @ syntax sugar:
@time_loggerdef target_function(): pass
Equivalent to:
def target_function(): pass target_function = time_logger(target_function)
This mechanism allows us to add functionality (such as logging, permissions, etc.) uniformly without modifying the original function.
* * *
## Example: Printing Logs
def my_decorator(func):
def wrapper():
print("Before function execution")
func()
print("After function execution")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
Output:
Before function executionHello!After function execution
* `my_decorator` receives `say_hello`
* `@my_decorator` replaces the original function
* * *
### Decorators with Parameters
If the original function has parameters, you need to use `*args, **kwargs` in the `wrapper`:
## Example
def my_decorator(func):
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:
Before executionHello, Alice!After execution
**Note:** Using `*args, **kwargs` allows compatibility with functions of any parameters.
* * *
## Decorators with Parameters (Advanced)
def repeat(num_times):
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()
**Note:** This is a "decorator factory", where the outer function is used to receive parameters.
Hello!Hello!Hello!
!(#)
* * *
## Class Decorators
In addition to functions, decorators can also be applied to classes.
Class decorators receive a class and return a modified class or wrapped class.
* Enhance class methods
* Control instantiation process
* Implement singleton, logging, and other features
* * *
### Function-style Class Decorators
## Example
def log_class(cls):
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 callOriginal methodAfter call
* * *
### Class-style Class Decorators
## Example: Singleton Pattern
class SingletonDecorator:
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)
InitializationTrue
* * *
## Built-in Decorators
Commonly used built-in decorators:
1. **@staticmethod**: Defines a static method
2. **@classmethod**: Defines a class method
3. **@property**: Converts a method to a property
## Example
class MyClass:
@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 decorators **wrap the function from bottom to top during the definition phase**, and **execute from top to bottom during the call phase**:
## Example
def decorator1(func):
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 1Decorator 2Hello!
* * *
## Core Summary
Decorator = Function wrapping function + extending functionality without modifying original code
* The @ syntax is essentially function replacement
* wrapper is the actually executed function
* Recommended to use *args, **kwargs for better versatility
* Supports functions, classes, and even decorators with parameters
YouTip