定义
python装饰器接受一个可调用对象作为输入,并返回一个新的可调用对象
比较
函数装饰器 | 类装饰器 | 方法装饰器 | |
---|---|---|---|
参数 | 接受函数作为参数 | 接受类作为参数 | 接受方法(类的函数成员)作为参数 |
返回值 | 返回一个新函数 | 返回一个新类(通常是原始类的子类) | 通常返回原始方法或修改后的方法 |
应用场景 | 为函数添加额外的功能,如日志记录、计时、缓存等 | 修改类的行为或结构,如添加方法、修改元类等 | 修改或增强类中的方法行为 |
使用方式 | 使用@ 符号应用于函数定义之前 | 使用@ 符号应用于类定义之前 | 使用@ 符号应用于类的方法定义之前 |
复杂性 | 相对较低,主要关注函数的修改和增强 | 相对较高,需要处理类的继承、方法和属性等 | 适中,需要理解类和方法的上下文 |
性能 | 通常性能较好,因为不涉及类的创建和继承 | 性能可能略逊于函数装饰器,但通常可以接受 | 性能通常与函数装饰器相似 |
类装饰器
类装饰器提供了更多的灵活性和封装性
类可以包含状态(通过实例变量)和行为(通过方法)
- 状态管理
- 可配置性
- 多个装饰器
- 代码组织
class MyDecorator: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print("Before function call") result = self.func(*args, **kwargs) print("After function call") return result # 使用装饰器
@MyDecorator
def say_hello(name): print(f"Hello, {name}!") # 调用函数
say_hello("World")
描述符
-
__get__ /__set__
用于控制属性访问/赋值过程- 当一个对象作为另一个对象的属性被访问时,解释器会调用该对象的
__get__
方法 - 应用场景 访问控制/计算属性/缓存/数据验证/惰性加载
property
的本质是一个数据描述符,一个类- 实现了
__get__()
、__set__()
和__delete__()
方法 - 在使用
@property
装饰器时 - Python 解释器会将属性方法包装成 property 类的实例,并将其添加为类的属性
- 实现了
class Descriptor:def __get__(self, instance, owner):print(f"Getting attribute from {owner} instance")return "Return value from descriptor"class MyClass:attr = Descriptor()obj = MyClass()print(obj.attr)
- 当一个对象作为另一个对象的属性被访问时,解释器会调用该对象的
-
__getattr__
方法用于捕获对象属性访问的失败情况,备用 -
__getitem__
方法用于对象的索引访问操作
property 模拟
class PropertyDescriptor: def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel if doc is None and fget is not None: doc = fget.__doc__ self.__doc__ = doc def __get__(self, obj, objtype=None): if obj is None: return self if self.fget is None: raise AttributeError("unreadable attribute") return self.fget(obj) def __set__(self, obj, value): if self.fset is None: raise AttributeError("can't set attribute") self.fset(obj, value) def __delete__(self, obj): if self.fdel is None: raise AttributeError("can't delete attribute") self.fdel(obj) # 使用 PropertyDescriptor 类装饰器
class MyClass: def __init__(self): self._value = None @PropertyDescriptor def value(self): """Getter for the value.""" return self._value @value.setter def value(self, value): """Setter for the value.""" self._value = value @value.deleter def value(self): """Deleter for the value.""" del self._value # 示例用法
obj = MyClass()
obj.value = 42 # 调用 setter 方法
print(obj.value) # 调用 getter 方法,输出: 42
del obj.value # 调用 deleter 方法