@property 前世今生

定义

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 方法
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值