第79集:类装饰器
学习目标
- 理解类装饰器的概念
- 掌握类装饰器的语法
- 学会创建类装饰器
- 理解类装饰器的执行流程
- 掌握类装饰器与函数装饰器的区别
- 了解类装饰器的应用场景
什么是类装饰器
类装饰器是指使用类来实现的装饰器。类装饰器通过实现__call__方法使类实例可以像函数一样调用,从而实现装饰器的功能。
类装饰器的结构
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)基本语法
语法结构
@MyDecorator
def function():
pass等价形式
def function():
pass
function = MyDecorator(function)基本示例
示例1:简单类装饰器
class CountCalls:
"""调用计数装饰器"""
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"函数 {self.func.__name__} 已调用 {self.count} 次")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello!")
say_hello()
say_hello()示例2:计时装饰器
import time
class Timer:
"""计时装饰器"""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
start = time.time()
result = self.func(*args, **kwargs)
elapsed = time.time() - start
print(f"{self.func.__name__} 执行时间: {elapsed:.4f}秒")
return result
@Timer
def slow_function():
time.sleep(1)
print("函数执行完成")
slow_function()示例3:日志装饰器
class Logger:
"""日志装饰器"""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print(f"调用函数: {self.func.__name__}")
print(f"参数: args={args}, kwargs={kwargs}")
result = self.func(*args, **kwargs)
print(f"返回值: {result}")
return result
@Logger
def add(a, b):
return a + b
add(3, 5)类装饰器的执行流程
执行流程详解
class MyDecorator:
def __init__(self, func):
print(f"1. __init__ 被调用,函数: {func.__name__}")
self.func = func
def __call__(self, *args, **kwargs):
print(f"3. __call__ 被调用")
result = self.func(*args, **kwargs)
print(f"5. 函数执行完成")
return result
@MyDecorator
def my_function():
print(f"4. 原函数执行")
print("2. 装饰器应用完成")
my_function()执行顺序
- 创建装饰器实例:
MyDecorator(my_function) - 调用
__init__方法,保存被装饰函数 - 将装饰器实例赋值给原函数名
- 调用函数时,调用装饰器实例的
__call__方法
类装饰器与函数装饰器的区别
区别1:状态管理
# 函数装饰器:需要使用闭包或全局变量
count = 0
def count_calls(func):
def wrapper(*args, **kwargs):
global count
count += 1
print(f"调用次数: {count}")
return func(*args, **kwargs)
return wrapper
# 类装饰器:使用实例属性
class CountCalls:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"调用次数: {self.count}")
return self.func(*args, **kwargs)区别2:代码组织
# 函数装饰器:嵌套函数
def decorator(func):
def wrapper(*args, **kwargs):
pass
return wrapper
# 类装饰器:类方法
class Decorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
pass区别3:扩展性
# 类装饰器更容易扩展
class AdvancedDecorator:
def __init__(self, func, option1=None, option2=None):
self.func = func
self.option1 = option1
self.option2 = option2
def __call__(self, *args, **kwargs):
pass
def helper_method(self):
pass带参数的类装饰器
示例4:带参数的类装饰器
class Repeat:
"""重复执行装饰器"""
def __init__(self, times):
self.times = times
def __call__(self, func):
def wrapper(*args, **kwargs):
for i in range(self.times):
print(f"第{i+1}次执行:")
func(*args, **kwargs)
return wrapper
@Repeat(times=3)
def say_hello():
print("Hello!")
say_hello()示例5:带参数的日志装饰器
class Log:
"""带参数的日志装饰器"""
def __init__(self, level="INFO", prefix=""):
self.level = level
self.prefix = prefix
def __call__(self, func):
def wrapper(*args, **kwargs):
print(f"[{self.level}] {self.prefix} 调用 {func.__name__}")
result = func(*args, **kwargs)
print(f"[{self.level}] {self.prefix} 返回 {result}")
return result
return wrapper
@Log(level="DEBUG", prefix="API:")
def add(a, b):
return a + b
add(3, 5)类装饰器的应用
应用1:权限验证
class RequirePermission:
"""权限验证装饰器"""
def __init__(self, permission):
self.permission = permission
def __call__(self, func):
def wrapper(*args, **kwargs):
if not self.has_permission():
raise PermissionError(f"需要{self.permission}权限")
return func(*args, **kwargs)
return wrapper
def has_permission(self):
return self.permission == "admin"
@RequirePermission("admin")
def delete_user(user_id):
print(f"删除用户: {user_id}")
delete_user(123)应用2:缓存装饰器
class Cache:
"""缓存装饰器"""
def __init__(self, max_size=128):
self.max_size = max_size
self.cache = {}
def __call__(self, func):
def wrapper(*args, **kwargs):
key = (args, frozenset(kwargs.items()))
if key in self.cache:
print("从缓存获取")
return self.cache[key]
if len(self.cache) >= self.max_size:
self.cache.popitem()
result = func(*args, **kwargs)
self.cache[key] = result
print("计算并缓存")
return result
return wrapper
@Cache(max_size=3)
def expensive_function(x):
print(f"计算 {x}")
return x ** 2
expensive_function(5)
expensive_function(5)应用3:重试装饰器
import time
class Retry:
"""重试装饰器"""
def __init__(self, max_attempts=3, delay=1):
self.max_attempts = max_attempts
self.delay = delay
def __call__(self, func):
def wrapper(*args, **kwargs):
attempts = 0
while attempts < self.max_attempts:
try:
return func(*args, **kwargs)
except Exception as e:
attempts += 1
if attempts >= self.max_attempts:
raise
print(f"重试 {attempts}/{self.max_attempts}: {e}")
time.sleep(self.delay)
return wrapper
@Retry(max_attempts=3, delay=0.5)
def unreliable_function():
import random
if random.random() < 0.7:
raise ValueError("随机错误")
return "成功"
unreliable_function()应用4:性能监控
import time
class PerformanceMonitor:
"""性能监控装饰器"""
def __init__(self, threshold=1.0):
self.threshold = threshold
def __call__(self, func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start
if elapsed > self.threshold:
print(f"警告: {func.__name__} 执行时间 {elapsed:.2f}秒 超过阈值")
else:
print(f"{func.__name__} 执行时间 {elapsed:.4f}秒")
return result
return wrapper
@PerformanceMonitor(threshold=0.5)
def fast_function():
time.sleep(0.1)
@PerformanceMonitor(threshold=0.5)
def slow_function():
time.sleep(1.0)
fast_function()
slow_function()类装饰器的特殊方法
示例6:使用__get__方法
class MethodDecorator:
"""方法装饰器"""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print(f"调用方法: {self.func.__name__}")
return self.func(*args, **kwargs)
def __get__(self, instance, owner):
if instance is None:
return self
return lambda *args, **kwargs: self(instance, *args, **kwargs)
class MyClass:
@MethodDecorator
def my_method(self):
print("方法执行")
obj = MyClass()
obj.my_method()示例7:使用__getattribute__方法
class AccessLogger:
"""访问日志装饰器"""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print(f"访问函数: {self.func.__name__}")
return self.func(*args, **kwargs)
@AccessLogger
def my_function():
return "结果"
my_function()类装饰器的组合
示例8:多个类装饰器
class Timer:
"""计时装饰器"""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
import time
start = time.time()
result = self.func(*args, **kwargs)
elapsed = time.time() - start
print(f"执行时间: {elapsed:.4f}秒")
return result
class Logger:
"""日志装饰器"""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print(f"调用函数: {self.func.__name__}")
result = self.func(*args, **kwargs)
print(f"返回值: {result}")
return result
@Logger
@Timer
def add(a, b):
return a + b
add(3, 5)示例9:类装饰器与函数装饰器混合
class Timer:
"""计时装饰器"""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
import time
start = time.time()
result = self.func(*args, **kwargs)
elapsed = time.time() - start
print(f"执行时间: {elapsed:.4f}秒")
return result
def log(func):
"""日志装饰器"""
def wrapper(*args, **kwargs):
print(f"调用函数: {func.__name__}")
result = func(*args, **kwargs)
print(f"返回值: {result}")
return result
return wrapper
@log
@Timer
def multiply(a, b):
return a * b
multiply(4, 6)类装饰器的限制
限制1:不能直接装饰类方法
class Decorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
class MyClass:
@Decorator
def my_method(self):
pass
# 需要使用__get__方法
class MethodDecorator:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
if instance is None:
return self
return lambda *args, **kwargs: self(instance, *args, **kwargs)限制2:不能直接装饰类
# 类装饰器只能装饰函数,不能装饰类
@Decorator
class MyClass:
pass
# 需要使用函数装饰器来装饰类
def class_decorator(cls):
return cls
@class_decorator
class MyClass:
pass最佳实践
实践1:使用functools.wraps
from functools import wraps
class MyDecorator:
def __init__(self, func):
self.func = func
wraps(func)(self)
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)实践2:清晰的命名
class CountCallsDecorator:
"""清晰的命名"""
def __init__(self, func):
self.func = func
self.call_count = 0
def __call__(self, *args, **kwargs):
self.call_count += 1
return self.func(*args, **kwargs)实践3:文档化装饰器
class TimerDecorator:
"""
计时装饰器
用于测量函数执行时间
"""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
import time
start = time.time()
result = self.func(*args, **kwargs)
elapsed = time.time() - start
print(f"执行时间: {elapsed:.4f}秒")
return result实践4:提供辅助方法
class AdvancedDecorator:
def __init__(self, func):
self.func = func
self.call_count = 0
def __call__(self, *args, **kwargs):
self.call_count += 1
return self.func(*args, **kwargs)
def get_call_count(self):
"""获取调用次数"""
return self.call_count
def reset_call_count(self):
"""重置调用次数"""
self.call_count = 0常见错误
错误1:忘记实现__call__方法
# 错误:忘记实现__call__方法
class BadDecorator:
def __init__(self, func):
self.func = func
# 正确:实现__call__方法
class GoodDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)错误2:忘记保存原函数
# 错误:忘记保存原函数
class BadDecorator:
def __init__(self, func):
pass
def __call__(self, *args, **kwargs):
pass
# 正确:保存原函数
class GoodDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)错误3:忘记返回结果
# 错误:忘记返回结果
class BadDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
self.func(*args, **kwargs)
# 正确:返回结果
class GoodDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)总结
类装饰器是Python中强大的工具,具有以下特点:
核心概念
- 类装饰器通过实现
__call__方法实现 - 类装饰器使用实例属性管理状态
- 类装饰器可以更好地组织代码
优势
- 状态管理更方便
- 代码组织更清晰
- 扩展性更强
- 可以添加辅助方法
应用场景
- 调用计数
- 性能监控
- 权限验证
- 缓存控制
- 重试机制
掌握类装饰器将帮助你编写更灵活、更强大的Python代码。类装饰器是Python中重要的概念,理解它的工作原理对于编写高质量的Python程序至关重要。