1. Python类装饰器深度解析
在Python开发中,装饰器(Decorator)是提升代码复用性和可维护性的利器。而基于类的装饰器(Class-based Decorator)相比函数式装饰器,提供了更强大的封装能力和状态管理特性。我第一次在真实项目中应用类装饰器,是为了实现一个带缓存机制的API调用限流器,从此对这种模式有了全新认识。
类装饰器的核心优势在于它能保持装饰状态(通过实例属性)、实现更复杂的初始化逻辑,并且天然支持面向对象的继承和多态特性。下面通过六个关键维度,带你彻底掌握这种进阶装饰器实现方式。
2. 类装饰器核心机制剖析
2.1 类装饰器基本结构
一个最简类装饰器实现如下:
python复制class SimpleDecorator:
def __init__(self, func):
self.func = func # 保存被装饰函数
def __call__(self, *args, **kwargs):
print(f"Calling {self.func.__name__}")
return self.func(*args, **kwargs)
@SimpleDecorator
def greet(name):
return f"Hello, {name}"
print(greet("Alice"))
# 输出:
# Calling greet
# Hello, Alice
关键点解析:
__init__接收被装饰函数并进行初始化__call__使得实例可像函数一样调用- 装饰器实例会替换原函数,因此需要手动调用保存的原函数
2.2 带参数的类装饰器
当需要配置装饰器行为时,需要支持参数传递:
python复制class ParametrizedDecorator:
def __init__(self, max_calls=3):
self.max_calls = max_calls
def __call__(self, func):
self.func = func
self.call_count = 0
return self._wrapper
def _wrapper(self, *args, **kwargs):
if self.call_count >= self.max_calls:
raise RuntimeError("Max calls exceeded")
self.call_count += 1
return self.func(*args, **kwargs)
@ParametrizedDecorator(max_calls=2)
def api_call():
print("API called")
api_call() # 成功
api_call() # 成功
api_call() # 抛出RuntimeError
参数处理流程:
- 装饰器参数先传给
__init__ __call__接收被装饰函数- 返回实际执行的包装方法
3. 高级应用场景实现
3.1 状态保持装饰器
类装饰器非常适合需要维护状态的场景,比如实现函数调用计数器:
python复制class CallCounter:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"{self.func.__name__} called {self.count} times")
return self.func(*args, **kwargs)
@CallCounter
def process_data(data):
return data.upper()
process_data("test") # 输出: process_data called 1 times
process_data("demo") # 输出: process_data called 2 times
3.2 方法装饰器
类装饰器也可以用于装饰类方法,此时需要处理self参数:
python复制class MethodDecorator:
def __init__(self, method):
self.method = method
def __call__(self, instance, *args, **kwargs):
print(f"Calling {instance.__class__.__name__}.{self.method.__name__}")
return self.method(instance, *args, **kwargs)
class MyClass:
@MethodDecorator
def show(self, x):
print(f"Value: {x}")
obj = MyClass()
obj.show(42) # 输出: Calling MyClass.show\nValue: 42
4. 生产级实践技巧
4.1 保留函数元数据
装饰器会覆盖原函数的__name__、__doc__等元数据,使用functools.wraps解决:
python复制from functools import update_wrapper
class MetaPreservingDecorator:
def __init__(self, func):
self.func = func
update_wrapper(self, func)
def __call__(self, *args, **kwargs):
print("Decorator logic here")
return self.func(*args, **kwargs)
@MetaPreservingDecorator
def documented_func():
"""This is a docstring"""
pass
print(documented_func.__name__) # 输出: documented_func
print(documented_func.__doc__) # 输出: This is a docstring
4.2 实现装饰器堆叠
类装饰器可以与其他装饰器组合使用:
python复制class DecoratorA:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("DecoratorA before")
result = self.func(*args, **kwargs)
print("DecoratorA after")
return result
class DecoratorB:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("DecoratorB before")
result = self.func(*args, **kwargs)
print("DecoratorB after")
return result
@DecoratorA
@DecoratorB
def target_function():
print("Target function")
target_function()
# 输出:
# DecoratorA before
# DecoratorB before
# Target function
# DecoratorB after
# DecoratorA after
5. 性能优化与调试
5.1 使用__get__实现方法绑定
对于类方法装饰器,更专业的实现方式是使用描述符协议:
python复制class MethodDecoratorAdvanced:
def __init__(self, method):
self.method = method
def __call__(self, instance, *args, **kwargs):
print("Advanced decoration")
return self.method(instance, *args, **kwargs)
def __get__(self, instance, owner):
# 返回绑定到实例的callable
from functools import partial
return partial(self.__call__, instance)
class MyClass:
@MethodDecoratorAdvanced
def process(self, x):
return x * 2
obj = MyClass()
print(obj.process(21)) # 输出: Advanced decoration\n42
5.2 异步函数支持
处理async函数的类装饰器需要返回协程:
python复制class AsyncDecorator:
def __init__(self, func):
self.func = func
async def __call__(self, *args, **kwargs):
print("Async decoration started")
result = await self.func(*args, **kwargs)
print("Async decoration finished")
return result
@AsyncDecorator
async def async_task():
print("Task running")
return 42
import asyncio
print(asyncio.run(async_task()))
# 输出:
# Async decoration started
# Task running
# Async decoration finished
# 42
6. 实战案例:重试机制实现
最后看一个生产环境中常用的重试装饰器实现:
python复制import time
from functools import update_wrapper
class RetryDecorator:
def __init__(self, max_retries=3, delay=1, exceptions=(Exception,)):
self.max_retries = max_retries
self.delay = delay
self.exceptions = exceptions
def __call__(self, func):
def wrapper(*args, **kwargs):
last_error = None
for attempt in range(1, self.max_retries + 1):
try:
return func(*args, **kwargs)
except self.exceptions as e:
last_error = e
if attempt < self.max_retries:
time.sleep(self.delay)
raise RuntimeError(f"Failed after {self.max_retries} attempts") from last_error
update_wrapper(wrapper, func)
return wrapper
@RetryDecorator(max_retries=2, exceptions=(ValueError,))
def risky_operation(x):
if x < 0.8: # 模拟失败条件
raise ValueError("Invalid input")
return x * 100
print(risky_operation(0.9)) # 一次成功
print(risky_operation(0.7)) # 重试两次后失败
这个实现包含了:
- 可配置的重试次数和延迟
- 指定捕获的异常类型
- 完善的错误传播机制
- 函数元数据保留
类装饰器在复杂场景下展现出强大优势,特别是在需要维护状态、支持复杂初始化或实现描述符协议时。掌握这种模式能让你的装饰器代码更加灵活和强大。