Python中的类装饰器是通过自定义类来实现装饰器功能的方式,它和函数装饰器一样可以对其他函数或类进行功能增强,核心依托于类的__call__方法实现可调用特性。

类装饰器的基本原理
类装饰器的本质是一个接收被装饰对象作为参数的类,当使用@类装饰器名语法装饰其他对象时,会先实例化装饰器类,将被装饰对象传入类的初始化方法,之后在调用被装饰对象时,实际会调用装饰器类的__call__方法,从而可以在__call__方法中添加额外的逻辑。
基础类装饰器实现
最简单的类装饰器只需要实现__init__和__call__两个方法,下面是一个统计函数执行次数的类装饰器示例:
class CountCall:
def __init__(self, func):
# 保存被装饰的函数
self.func = func
# 初始化调用次数
self.call_count = 0
def __call__(self, *args, **kwargs):
# 调用次数加1
self.call_count += 1
print(f"{self.func.__name__} 已被调用 {self.call_count} 次")
# 执行被装饰的函数
return self.func(*args, **kwargs)
# 使用类装饰器装饰函数
@CountCall
def add(a, b):
return a + b
# 测试调用
print(add(1, 2))
print(add(3, 4))
运行上述代码后,会先输出函数的调用次数,再输出函数的执行结果,说明类装饰器已经成功生效。
带参数的类装饰器
如果需要给类装饰器传递参数,就需要在装饰器类外层再包裹一层,或者调整类的结构,让__init__方法接收装饰器参数,__call__方法返回真正的装饰逻辑。下面是一个带参数的日志类装饰器示例,可以指定日志的前缀内容:
class LogDecorator:
def __init__(self, prefix="日志"):
# 接收装饰器传入的参数
self.prefix = prefix
def __call__(self, func):
# 定义内部包装函数
def wrapper(*args, **kwargs):
print(f"{self.prefix}:开始执行 {func.__name__} 函数")
result = func(*args, **kwargs)
print(f"{self.prefix}:{func.__name__} 函数执行结束")
return result
return wrapper
# 使用带参数的类装饰器
@LogDecorator(prefix="业务日志")
def multiply(x, y):
return x * y
# 测试调用
print(multiply(5, 6))
类装饰器装饰类
类装饰器不仅可以装饰函数,还可以装饰其他类,用来给被装饰的类添加属性或者修改类的行为。下面是一个给类添加额外属性的类装饰器示例:
class AddAttribute:
def __init__(self, cls):
# 保存被装饰的类
self.cls = cls
def __call__(self, *args, **kwargs):
# 实例化被装饰的类
instance = self.cls(*args, **kwargs)
# 给实例添加额外属性
instance.create_time = "2024-01-01"
return instance
# 使用类装饰器装饰类
@AddAttribute
class User:
def __init__(self, name):
self.name = name
# 测试
user = User("张三")
print(f"用户名:{user.name},创建时间:{user.create_time}")
类装饰器和函数装饰器的区别
类装饰器和函数装饰器的核心功能一致,但是存在以下差异:
- 类装饰器可以保存状态,比如前面示例中的调用次数,而函数装饰器如果要保存状态需要使用闭包或者 nonlocal 关键字
- 类装饰器的结构更清晰,当装饰逻辑比较复杂时,拆分成多个方法维护起来更方便
- 函数装饰器的实现更简洁,适合简单的装饰逻辑场景
使用注意事项
在使用类装饰器时需要注意,被装饰的函数或类的元信息(比如__name__、__doc__)可能会被修改,如果需要保留原对象的元信息,可以在__call__方法中使用functools.wraps来处理,和函数装饰器的处理方式一致。
import functools
class KeepMeta:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
@functools.wraps(self.func)
def wrapper(*args, **kwargs):
return self.func(*args, **kwargs)
return wrapper
@KeepMeta
def test_func():
"""测试函数的文档字符串"""
pass
print(test_func.__name__) # 输出 test_func,而不是 wrapper
print(test_func.__doc__) # 输出 测试函数的文档字符串
Python类装饰器装饰器__call__方法修改时间:2026-07-18 02:00:24