一、基本原理
使用类实现装饰器的基本原理:
- 定义一个类,
__init__
方法用于初始化装饰器的状态,__call__
方法用于定义在调用被装饰函数时所执行的逻辑。 - 通过类创建一个可调用对象(类的实例),该对象在被调用时执行
__call__
方法中的装饰逻辑。
二、Demo 示例
示例 1:简单的类装饰器
import functools
class SimpleDecorator:
def __init__(self, func):
self.func = func
functools.wraps(func)(self)
def __call__(self, *args, **kwargs):
print("Before function execution")
result = self.func(*args, **kwargs)
print("After function execution")
return result
@SimpleDecorator
def my_function():
"""This is the original function."""
print("Function is being executed")
my_function()
print(my_function.__name__) # 输出 "my_function"
输出结果:
Before function execution
Function is being executed
After function execution
my_function
在这个例子中,SimpleDecorator
类实现了一个简单的装饰器,它在被装饰函数执行前后打印额外的信息。
- 使用
@SimpleDecorator
装饰函数my_function
时,相当于执行了:my_function = SimpleDecorator(my_function)
。 my_function
是SimpleDecorator
类的实例,由于在类中定义了__call__
方法,因此my_function
是一个可调用对象,可以像函数一样调用。- 执行
my_function()
时,调用__call__
方法中定义的装饰逻辑,实现装饰器的效果。
functools.wraps(func)(self)
的理解:
functools.wraps(func)(self)
等价于两个步骤:- 创建装饰器:
decorator = functools.wraps(func)
- 使用装饰器:
decorator(self)
- 创建装饰器:
- d
ecorator = functools.wraps(func)
的作用是将函数func
的元信息(如名称、文档字符串等)复制给被装饰函数(在这里是__call__
方法)。 decorator(self)
的作用将__call__
方法的实例对象传递给decorator
装饰器,这个过程实际上是在调用decorator
装饰器 ,并将__call__
方法作为参数传递进去。
示例 2:带参数的类装饰器
import functools
class ParametrizedDecorator:
def __init__(self, param):
self.param = param
def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"Decorator parameter: {self.param}")
for i in range(self.param):
func(*args, **kwargs)
return wrapper
@ParametrizedDecorator(param=3)
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
print(greet.__name__) # 输出 "greet"
输出结果:
Decorator parameter: 3
Hello, Alice!
Hello, Alice!
Hello, Alice!
greet
这个例子中,ParametrizedDecorator
接受一个参数,并在装饰函数执行前打印该参数。
- 使用
@ParametrizedDecorator(param=3)
装饰greet
函数,相当于:greet = ParametrizedDecorator(param=3)(greet)
。 - 在执行
ParametrizedDecorator(param=3)(greet)
时,调用了__call__
方法,返回一个新的wrapper
函数,此时greet
方法相当于
wrapper
函数的引用。 - 执行
greet("Alice")
等同于执行wrapper("Alice")
,从而实现了装饰器的效果。
三、要点小结
- 在类中定义
__call__
方法,可以将类的实例变为可调用对象,使其可以像函数一样被调用。 - 当对象被调用时,会执行
__call__
方法中的逻辑。可利用这一特性通过定义__call__
方法中的逻辑实现装饰效果。 - 可以通过在
__init__
方法中接受参数来实现带参数的类装饰器,这使得类装饰器更加灵活,可以根据传递的参数定制装饰行为。