用Python类实现装饰器
为什么使用类实现装饰器?
在某些情况下,我们可能希望装饰器保存状态、初始化一些参数,或者通过对象的方法操作。这时,用类实现装饰器会显得更为灵活和合理。类装饰器允许我们:
- 通过类的属性来存储状态。
- 利用类的构造函数传递参数。
- 通过类方法提供复杂的行为逻辑。
类装饰器的实现
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("Function is being called from class-based decorator")
return self.func(*args, **kwargs)
@MyDecorator
def say_hello():
print("Hello, world!")
say_hello()
在这个例子中,MyDecorator 类的 init 方法接收被装饰的函数,并将其保存为类的一个属性。call 方法则使该类的实例可以像函数一样被调用,这就是为什么我们可以像函数装饰器一样使用 @MyDecorator 来装饰 say_hello 函数。
增加状态的类装饰器
通过类装饰器,我们可以轻松地维护状态。假设我们想跟踪某个函数被调用的次数,可以通过以下方式实现:
class CallCounter:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"Function has been called {self.count} times")
return self.func(*args, **kwargs)
@CallCounter
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
greet("Bob")
带参数的类装饰器
类装饰器的另一个强大功能是能够接收参数。为了实现这一点,我们可以通过 init 方法接受更多的参数。假设我们想实现一个带有自定义前缀的日志记录器,可以这样写:
class Logger:
def __init__(self, prefix):
self.prefix = prefix
def __call__(self, func):
def wrapper(*args, **kwargs):
print(f"{self.prefix}: Function {func.__name__} is called")
return func(*args, **kwargs)
return wrapper
@Logger("INFO")
def process_data(data):
print(f"Processing {data}")
process_data("Dataset 1")