属性描述符

1、为什么需要属性描述符?

先看个例子
这里写图片描述
在这个例子中我们对user的年龄进行了处理,如果我们好要继续验证name和email是不是字符串类型,那么还需要分别编写两个属性函数分别检查name和email是不是字符串类型,都是检查字符串,这里如果使用属性函数来检查,我们就重复写了代码,如果有更多的属性需要做相同的处理,重复的代码会更多,所以这就需要属性描述符来避免代码的重复编写

2、什么是描述符(descriptor)?

  python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问。这些方法有 __get__(), __set__(), 和__delete__()。如果这些方法中的任何一个被定义在一个对象中,这个对象就是一个描述符。
  
这里写图片描述
上面的例子中呈现了将age设置成30后程序是如何调用的,在程序中打个断点,debug下,可以看到程序进入了 __set__()方法,红色方框中是被调用后三个参数的结果,那么我们可以在 __set__()方法中写检查逻辑,当我们改变age属性时会进入该方法中进行验证,接下来写检查逻辑,检查设置的age是否是int类型
这里写图片描述
这里写图片描述
当我们输入字符串就会报错

3、什么是数据描述符,什么是非数据描述符?

一个类,如果只定义了 get() 方法,而没有定义 set(), delete() 方法,则认为是非数据描述符; 反之,则成为数据描述符(data descriptor)

4、__dict__

请参考https://www.cnblogs.com/zjchao/p/7894477.html

5、属性查找顺序总结

以上归根到底还是一个属性优先级查找问题,之前的博客中有提到__getattribute__和__getattr__两个方法也是关于属性查找的,请看__getattr__和__getattribute__
https://blog.csdn.net/f1ngf1ngy1ng/article/details/80583985,属性查找还涉及实例属性和类属性,本篇博客又提到了属性描述符,又是关于属性优先查找问题,最后在这里关于这些问题做个总结

1、 __getattribute__, 无条件调用

2、数据描述符:由 1触发调用 (若人为的重载了该 getattribute(方法,可能会无法调用描述符)

3、实例对象的字典obj.__dict__(若与描述符对象同名,会被覆盖哦)

4、类的字典cls.__dict__

5、非数据描述符

6、父类的字典

7、__getattr__方法



结合上面例子讲解user.age的属性查找顺序:

如果user是某个类的实例,那么user.age(以及等价的getattr(user, ‘age’)),首先调用__getattribute__,如果类定义了__getattr__方法,那么在__getattribute__抛出AttributeError的时候就会调用__getattr__,而对于描述符(__get__)的调用,则是发生在__getattribute__内部的

user = User(),那么user.sge顺序如下:
(1)如果“age”是出现在User或其基类的__dict__中,且age是data descriptor,那么调用其__get__方法,否则
(2)如果“age”出现在obj的dict中,那么直接返回obj.__dict__[‘age’],否则
(3)如果“age”是出现在User或其基类的__dict__中
(3.1)如果age是non-data descriptor,那么调用其__get__方法,否则
(3.2)返回__dict__[‘age’]
(4)如果User有__getattr__方法,调用__getattr__方法,否则
(5)抛出AttributeError

猜你喜欢

转载自blog.csdn.net/f1ngf1ngy1ng/article/details/80583934