描述符

 

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:\python35\python3.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:\python35\python3.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:\python35\python3.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:\python35\python3.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:\python35\python3.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:\python35\python3.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:\python35\python3.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:\python35\python3.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:\python35\python3.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:\python35\python3.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:\python35\python3.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:\python35\python3.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:\python35\python3.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:\python35\python3.exe D:/pyproject/day28/描述符优先级.py

{'x': 1}
posted @ 2018-06-23 10:12  gouguoqi  阅读(235)  评论(0编辑  收藏  举报