zoukankan      html  css  js  c++  java
  • 描述符

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法")
        def __delete__(self, instance):
            print("delete方法")
    f1=Foo()#实例化一个实例f1
    f1.name="gouguoqi"#给实例增加一个属性name赋值为gouguoqi
    print(f1.name)#打印下实例的属性
    
    C:python35python3.exe D:/pyproject/day28/描述符.py
    
    gouguoqi

    但是为什么赋值和调用的时候都没有触发__get__和__set__呢

    1、也就是说在自己的类里面是触发不了的,需要在另外一个类里面用(在何地用?)

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法")
        def __delete__(self, instance):
            print("delete方法")
    f1=Foo()#实例化一个实例f1
    print(Foo())
    f1.name="gouguoqi"#给实例增加一个属性name赋值为gouguoqi
    print(f1.name)#打印下实例的属性
    del f1.name#删除f1的name属性
    class Bar:
        x=Foo()#定义了一个Bar的数据属性x,值是Foo实例化的一个结果
    
    C:python35python3.exe D:/pyproject/day28/描述符.py
    
    <__main__.Foo object at 0x0000000000A44470>
    
    gouguoqi

    因为Foo这类具备三个方法__get__   __set__   __delete__ 又把Foo定义成了Bar的类属性,所以这个Foo就是一个描述符

    2、知道描述符在什么位置定义了,那什么时候会触发呢

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法")
        def __delete__(self, instance):
            print("delete方法")
    f1=Foo()#实例化一个实例f1
    f1.name="gouguoqi"#给实例增加一个属性name赋值为gouguoqi
    class Bar:
        x=Foo()#定义了一个Bar的数据属性x,值是Foo实例化的一个结果
    b1=Bar()#实例化一个b1的实例
    b1.x#调用实例b1的x属性,x就是描述符Foo,所以就会触发描述符的__get__
    
    #前提是另外的一个类产生的实例去调用描述符
    
    C:python35python3.exe D:/pyproject/day28/描述符.py
    
    get方法

    3、现在触发了__get__方法了,其他的2种方法如何触发呢

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法")
        def __delete__(self, instance):
            print("delete方法")
    f1=Foo()#实例化一个实例f1
    f1.name="gouguoqi"#给实例增加一个属性name赋值为gouguoqi
    class Bar:
        x=Foo()#定义了一个Bar的数据属性x,值是Foo实例化的一个结果
    b1=Bar()#实例化一个b1的实例
    b1.x#调用实例b1的x属性,x就是描述符Foo,所以就会触发描述符的__get__
    #前提是另外的一个类产生的实例去调用描述符
    b1.x=1#赋值
    del b1.x#删除
    
    C:python35python3.exe D:/pyproject/day28/描述符.py
    
    get方法
    
    set方法
    
    delete方法

    4、看一下b1的属性字典里面有没有东西

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法")
        def __delete__(self, instance):
            print("delete方法")
    f1=Foo()#实例化一个实例f1
    f1.name="gouguoqi"#给实例增加一个属性name赋值为gouguoqi
    class Bar:
        x=Foo()#定义了一个Bar的数据属性x,值是Foo实例化的一个结果
    b1=Bar()#实例化一个b1的实例
    # b1.x#调用实例b1的x属性,x就是描述符Foo,所以就会触发描述符的__get__
    #前提是另外的一个类产生的实例去调用描述符
    b1.x=1#赋值,会触发__set__方法,只是打印了一下,啥也没干
    print(b1.x)#调用,会触发__get__方法,没有return默认是None
    print(b1.__dict__)#查看b1的属性字典,是空的,因为啥也没干,就只是打印了一下
    
    C:python35python3.exe D:/pyproject/day28/描述符.py
    
    set方法
    
    get方法
    
    None
    
    {}

    5、描述符分两种

    (1)数据描述符:至少实现了__get__()和__set__()

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法")

    (2)非数据描述符:没有实现__set__()

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")

    注意事项:

    一、描述符本身应该定义成新式类,被代理的类也应该是新式类

    二、必须把描述符定义成另外一个类的类属性,不能定义到构造函数中

    三、要严格遵循该优先级,优先级由高到低分别是

    1、类属性

    2、数据描述符

    3、实例属性

    4、非数据描述符

    5、找不到的属性触发__getattr__()

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法")
        def __delete__(self, instance):
            print("delete方法")
    f1=Foo()#实例化一个实例f1
    f1.name="gouguoqi"#给实例增加一个属性name赋值为gouguoqi
    class Bar:
        x=Foo()#定义了一个Bar的数据属性x,值是Foo实例化的一个结果
        def __init__(self,n):
            self.x=n# self.x=n等价于b1.x=1就是在给x赋值,而x就是描述符Foo()
    b1=Bar(10)#实例化一个b1的实例
    
    print(b1.__dict__)#查看b1的属性字典是空的
    
    C:python35python3.exe D:/pyproject/day28/描述符.py
    
    set方法
    
    {} 

    去掉描述符之后,在看下b1的属性字典

    因为去掉描述符之后,就跟上一个类没关系了,所以就是给当前的这个类进行简单的赋值操作了,肯定会到自己的实例的属性字典里面去

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法")
        def __delete__(self, instance):
            print("delete方法")
    f1=Foo()#实例化一个实例f1
    f1.name="gouguoqi"#给实例增加一个属性name赋值为gouguoqi
    class Bar:
        # x=Foo()#定义了一个Bar的数据属性x,值是Foo实例化的一个结果
        def __init__(self,n):
            self.x=n# self.x=n等价于b1.x=1就是在给x赋值,而x就是b1的属性
    b1=Bar(10)#实例化一个b1的实例
    print(b1.__dict__)
    
    C:python35python3.exe D:/pyproject/day28/描述符.py
    
    {'x': 10}

    6、只要Bar中的实例有赋值、调用、删除操作,都会触发描述符Foo中对应的set get delete等方法

    上面当我们操作b1的x的属性的时候不是会触发描述符Foo的set方法吗,但是属性字典是空的,那是因为set方法什么事情都没干,没有真正意义上的set,我们来改下

    先查看下instance和value是什么东西

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法",instance,value)#查看下instance和value是什么
    
    #instance就是Bar的实例b1
        def __delete__(self, instance):
            print("delete方法")
    class Bar:
        x=Foo()#定义了一个Bar的数据属性x,值是Foo实例化的一个结果
        def __init__(self,n):
            self.x=n# self.x=n等价于b1.x=1就是在给x赋值,而x就是描述符Foo()就会触发Foo的set
    b1=Bar(10)#实例化一个b1的实例
    
    C:python35python3.exe D:/pyproject/day28/描述符.py
    
    set方法 <__main__.Bar object at 0x0000000000D345C0> 10

    然后真正意义的实现一下set方法的作用

    这样只要触发到了Foo的__set__方法就会把属性放入到Bar的实例b1的属性字典里面

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法",instance,value)#查看下instance和value是什么
            instance.__dict__["x"]=value#等价于b1.__dict__["x"]=10
        def __delete__(self, instance):
            print("delete方法")
    class Bar:
        x=Foo()#定义了一个Bar的数据属性x,值是Foo实例化的一个结果
        def __init__(self,n):
            self.x=n# self.x=n等价于b1.x=1就是在给x赋值,而x就是描述符Foo()就会触发Foo的set
    b1=Bar(10)#实例化一个b1的实例
    print(b1.__dict__)
    
    C:python35python3.exe D:/pyproject/day28/描述符.py
    
    set方法 <__main__.Bar object at 0x0000000000D84550> 10
    
    {'x': 10} 

    我们赋值2次试试看,结果是第二次赋值的会覆盖第一次的值

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法",instance,value)#查看下instance和value是什么
            instance.__dict__["x"]=value#等价于b1.__dict__["x"]=10
        def __delete__(self, instance):
            print("delete方法")
    class Bar:
        x=Foo()#定义了一个Bar的数据属性x,值是Foo实例化的一个结果
        def __init__(self,n):
            self.x=n# self.x=n等价于b1.x=1就是在给x赋值,而x就是描述符Foo()就会触发Foo的set,第一次赋值
    b1=Bar(10)#实例化一个b1的实例
    print(b1.__dict__)
    b1.x=11#重新赋值一次
    print(b1.__dict__)#再次查看b1的属性字典
    
    C:python35python3.exe D:/pyproject/day28/描述符.py
    
    set方法 <__main__.Bar object at 0x0000000000B64588> 10
    
    {'x': 10}
    
    set方法 <__main__.Bar object at 0x0000000000B64588> 11
    
    {'x': 11}

    7、描述符的优先级

      1、类属性

      2、数据描述符

      3、实例属性

      4、非数据描述符

      5、找不到的属性触发__getattr__()

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法",instance,value)#查看下instance和value是什么
        def __delete__(self, instance):
            print("delete方法")
    class Bar:
        x=Foo()#定义了一个Bar的数据属性x,值是Foo实例化的一个结果
    b1=Bar()#实例化一个实例b1
    b1.x#调用b1的x
    print(b1.x)#调用b1的x,打印b1.x的返回值
    
    C:python35python3.exe D:/pyproject/day28/描述符优先级.py
    
    get方法
    
    get方法
    
    None

    7.1类属性优先级最高

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法",instance,value)#查看下instance和value是什么
        def __delete__(self, instance):
            print("delete方法")
    class Bar:
        x=Foo()#定义了一个Bar的数据属性x,值是Foo实例化的一个结果
    Bar.x=22#定义一个类的数据属性x,定义到了Bar这个类的__dict__属性字典里面
    b1=Bar()#实例化一个实例b1
    print(b1.x)#实例b1没有x,所以找类,类里面的x的就是22,跟描述符现在没有关系了,因为已经在类里面找到了
    
    C:python35python3.exe D:/pyproject/day28/描述符优先级.py
    
    22

    7.2如果没有定义类属性,就是数据描述符第二

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
        def __set__(self, instance, value):
            print("set方法",instance,value)#查看下instance和value是什么
        def __delete__(self, instance):
            print("delete方法")
    class Bar:
        x=Foo()#定义了一个数据描述符x
    # Bar.x=22#定义一个类的数据属性x
    b1=Bar()#实例化一个实例b1
    print(Bar.__dict__)#查看类的属性字典,
    print(b1.x)#实例b1没有x,所以找类,类里面的x的就是Foo这个对象,所以就触发了get方法
    
    C:python35python3.exe D:/pyproject/day28/描述符优先级.py
    
    {'x': <__main__.Foo object at 0x0000000000D3C748>, '__module__': '__main__', '__doc__': None, '__dict__': <attribute '__dict__' of 'Bar' objects>, '__weakref__': <attribute '__weakref__' of 'Bar' objects>}
    
    get方法
    
    None

    7.3实例属性优先级大于非数据描述符,什么是非数据描述符,就是没有__set__

    class Foo:
        def __get__(self, instance, owner):
            print("get方法")
    class Bar:
        x=Foo()#现在这个x就是一个非数据描述符
    b1=Bar()
    b1.x=1#给实例设置一个x的属性值为1
    print(b1.__dict__)#发现设置到了b1的属性字典里面,并没有触发Foo的set方法,因为就没有set
    
    C:python35python3.exe D:/pyproject/day28/描述符优先级.py
    
    {'x': 1}
  • 相关阅读:
    Rust 总章
    GO 总章
    vue引入d3
    echarts地图修改高亮颜色及区域界线颜色
    vue+element 树形穿梭框组件
    element表格上下固定,内容高度自适应
    echarts在dialog弹框中不显示的解决方案
    echarts 饼图给外层加边框
    selenium等待元素出现
    Pycharm永久激活
  • 原文地址:https://www.cnblogs.com/gouguoqilinux/p/9216458.html
Copyright © 2011-2022 走看看