一、前置说明
1、本节目标
- 了解如何使用类实现装饰器
2、相关回顾
二、主要内容
1、基本原理
- 定义一个类,
__init__
方法用于初始化装饰器的状态,__call__
方法用于定义在调用被装饰函数时所执行的逻辑。 - 通过类创建一个可调用对象(类的实例),该对象在被调用时执行
__call__
方法中的装饰逻辑。
2、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)
decorator = 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")
,从而实现了装饰器的效果。
三、后置说明
1、要点小结
- 在类中定义
__call__
方法,可以将类的实例变为可调用对象,使其可以像函数一样被调用。 - 当对象被调用时,会执行
__call__
方法中的逻辑。可利用这一特性通过定义__call__
方法中的逻辑实现装饰效果。 - 可以通过在
__init__
方法中接受参数来实现带参数的类装饰器,这使得类装饰器更加灵活,可以根据传递的参数定制装饰行为。
2、下节准备
- Python 使用装饰器隐式装饰一个类中的所有方法