定义
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 方法