python:属性访问+描述符(property的原理)

回顾实用属性的方法:

提倡使用getattr()

另一个使用实例的方法,用get、set的方式+property():

通过property()方法,使属性x和size挂钩

属性访问的魔法方法:

class C:
    def __getattribute__(self, name):
        print('getattribute')
        # 使用 super() 调用 object 基类的 __getattribute__ 方法
       return super().__getattribute__(name)  

    def __setattr__(self, name, value):
          print('setattr')
          super().__setattr__(name, value)

    def __delattr__(self, name):
        print('delattr')
       super().__delattr__(name)

    def __getattr__(self, name):
        print('getattr')

 

使用上述类的举例:

注意调用的顺序:访问一个属性时,先访问__getattribute__(),如果没有找到,才调用__getattr__()

注意别陷入死循环:

举例:

写一个矩形类,默认有宽和高两个属性;
如果为一个叫square的属性赋值,那么说明这是一个正方形,值就是正方形的边长,此时宽和高都应该等于边长。

如果按图写法会出现死循环:原因实例化时,self.width=width调用__setattr__(),而其中else语句又调用了__setattr__()魔法方法

 

正确写法:

class Rectangle:
    def __init__(self, width=0, height=0):
        self.width = width
        self.height = height

    def __setattr__(self, name, value):
        if name == 'square':
            self.width = value
            self.height = value
        else:
            self.__dict__[name] = value   #或者调用基类的super()的__setattr__(name,value)方法,推荐这种方法。

    def getArea(self):
        return self.width * self.height



描述符(property的原理)

描述符就是将某种特殊类型的类的实例指派给另一个类的属性。

什么是特殊类型?至少实现以下3个方法之一:
__get__(self, instance, owner)
用于访问属性,它返回属性的值
__set__(self, instance, value)
将在属性分配操作中调用,不返回任何内容
__delete__(self, instance)
控制删除操作,不返回任何内容

 

class MyDescriptor:
    def __get__(self, instance, owner):
        print("getting...", self, instance, owner)
        
    def __set__(self, instance, value):
        print("setting...", self, instance, value)
        
    def __delete__(self, instance):
        print("deleting...", self, instance)

class Test:
    x = MyDescriptor()

对以上定义的类进行测试:

注意观察每个魔法方法的返回值

再看一个演示:

class MyProperty:
   def __init__(self, fget=None, fset=None, fdel=None):
      self.fget = fget
      self.fset = fset
      self.fdel = fdel
      
   def __get__(self, instance, owner):
      return self.fget(instance)
   
   def __set__(self, instance, value):
      self.fset(instance, value)
      
   def __delete__(self, instance):
      self.fdel(instance)

class C:
   def __init__(self):
      self._x = None
      
   def getX(self):
      return self._x
   
   def setX(self, value):
      self._x = value
      
   def delX(self):
      del self._x
      
   x = MyProperty(getX, setX, delX)

实例化调用:

 

举例:

先定义一个温度类,然后定义两个描述符类用于描述摄氏度和华氏度两个属性。
要求两个属性会自动进行转换,也就是说你可以给摄氏度这个属性赋值,然后打印的华氏度属性是自动转换后的结果。

class Celsius:
    def __init__(self, value = 26.0):
        self.value = float(value)

    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, value):
        self.value = float(value)

class Fahrenheit:
    def __get__(self, instance, owner):
        return instance.cel * 1.8 + 32

    def __set__(self, instance, value):
        instance.cel = (float(value) - 32) / 1.8

class Temperature:
    cel = Celsius()
    fah = Fahrenheit()


实例化举例:

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值