天天看点

关于Python中 “描述符“ 的理解

这里引用一段代码来试图说明我对描述符的理解

class A():                   #定义关于摄氏度的描述符
    def __init__(self,value = 30.0):
        self.value = float(value)
        
    def __get__(self,instance,owner):  
        return self.value
    
    def __set__(self,instance,value):
        self.value = float(value)
        
class B():             #定义关于华氏度的描述符
    def __get__(self,instance,owner):  #摄氏度转华氏度
        return instance.cel*1.8+32

    def __set__(self,instance,value):  #华氏度转摄氏度
        instance.cel = (float(value)-32)/1.8
        
class T():                 
    cel = A()
    har = B()            #定义摄氏度属性cel与华氏度属性har
#运行结果如下
In[]: a = T()
In[]: a.cel

Out[]: 30.0

In[]: a.har

Out[]: 86.0

In[]: a.har = 70
In[]: a.cel

Out[]: 21.11111111111111

           

首先明确描述符的定义:

描述符就是一个具有绑定行为的对象属性,其属性访问将由描述符协议中的方法覆盖。这些方法为__get__、set__和__delete。如果这些方法中的任何一个针对某个对象定义,那么它就被认为是一个描述符

__get__方法是指当前属性的值被取得时则调用该方法

__set__方法是指当前属性的值被修改时则调用该方法

__delete__方法是指当前属性的值被删除时则调用该方法

参数instance表示当前实例化对象

参数owner表示当前实例化对象所属的类

来看代码

当使用a来实例化T类时,此时a内已经含有cel属性

a=T()

a.cel = 30

因为在a实例化T类时,首先自动调用了 A() 类内的__init__()方法,此时已经传值给value,使得a.cel得到value的值为30。

命令行调用a.har属性,返回得到86.0

In[] : a.har

Out[] : 86.0

def __get__(self,instance,owner):    #B类中__get__方法 属性值被取得时调用
        return instance.cel*1.8+32
           

这里是因为使用a.har时,自动调用了B类中的__get__()方法,则取得a.har的值

此处函数中的instance参数就是指当前实例a,返回值即是a.cel参与运算的运算结果,即是调用a.har的结果

In[]:a.har = 70

In[]:a.cel

Out[]:21.11111111111

此处修改属性a.har的值,再查看a.cel属性的值,发现随之改变

def __set__(self,instance,value):  #B类中的__set__方法 属性值被修改时调用
        instance.cel = (float(value)-32)/1.8
           
def __get__(self,instance,owner):   #A类中的__get__方法 属性值被取得时调用
        return self.value
           

a.har = 70这句语句触发时,标识实例化对象a的属性har值被修改,则此时自动调用har依托的B类中的__set__方法,此时传入函数的参数instance=实例化对象a,value = 70,进行将(70-32)/1.8 的结果赋值给a.cel的操作。

而给a.cel赋值,即调用了cel依托的A类中__set__方法并传入参数value = (70-32)/1.8 ,使得函数内self.value = (70-32)/1.8。

再次查看a.cel的值,则调用cel依托A类中的__get__方法返回当前cel属性的值,即为上赋值给该属性的(70-32)/1.8。

解释代码过程我使用了‘依托’这个词来表示属性与描述符之间的关系,实际上并不能这么理解,但是能力有限,也只能这样描述了。

整个代码过程相当于,使用a来对T类进行实例化时,在T类内含有属性cel与属性har,则实例化对象a含有cel与har两属性。通过cel = A()语句来实现cel与A类描述符的相关联,属性har同理。此时对两属性进行重写函数的操作时,则会自动调用你重写的相关操作的方法

第一次写这种博客,描述能力实在有限,大家愿意看下去的我在这里多谢了。如果理解有什么问题也欢迎大家评论区提出来或者留言,感谢感谢