【7.3】属性描述符和属性查找过程

属性描述符--利用的是抽象的方法, 把十几个字段共同的特性抽出来,每个字段都用这个特性,达到节省代码的目的。

属性描述符,有数据属性描述符和非数据属性描述符

   __get__

   __set__

   __delete__

  实现上述三个魔法函数其中之一即可成为属性描述符,如果只实现__get__称之为非数据属性描述符,只有同时实现__get__和__set__才称之为数据属性描述符

 1 #!/user/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import numbers
 4 
 5 
 6 class IntField:
 7     def __get__(self, instance, owner):
 8         return self.value
 9 
10     def __set__(self, instance, value):
11         if not isinstance(value, numbers.Integral):
12             raise ValueError('int value need')
13         if value < 0:
14             raise ValueError('positive value need')
15         self.value = value
16 
17     def __delete__(self, instance):
18         pass
19 
20 
21 class User:
22     age = IntField()
23 
24 
25 if __name__ == '__main__':
26     user = User()
27     user.age = 30
28     print(user.age)
29 
30     # ValueError('int value need')
31     # user.age = 'z'
32     # print(user.age)
33 
34     # ValueError('positive value need')
35     # user.age = -1
36     # print(user.age)
30

  总结一下:

    1.需要把校验放在一个类里面(IntField)

    2.需要重写魔法函数

    3.age = IntField()

    4.给age赋值的时候,会调用IntField里面的__get__方法

属性查找过程

  如果user是某个类的实例,那么user.age(以及等价的getattr(user,’age’)),首先调用__getattribute__。如果类定义了__getattr__方法,那么在__getattribute__抛出 AttributeError 的之前就会调用__getattr__,而对于描述符(__get__)的调用,则是发生在__getattribute__内部的。
user = User(), 那么user.age 顺序如下:
(1)如果“age”是出现在User类或其基类的__dict__中(类属性), 且age是data descriptor, 那么调用其__get__方法, 否则
(2)如果“age”出现在user的__dict__中(对象属性), 那么直接返回 obj.__dict__['age'], 否则  -->如果age不是类属性或者User不是数据属性描述符,则去对象属性中查找age
(3)如果“age”出现在User或其基类的__dict__中(类属性)
(3.1)如果age是non-data descriptor,那么调用其__get__方法, 否则
(3.2)返回 class.__dict__['age']
(4)如果User有__getattr__方法,调用__getattr__方法,否则  -->对象属性和类属性中都没有age,则调用User类的__getattr__方法
(5)抛出AttributeError

(3.1)

 1 #!/user/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import numbers
 4 
 5 
 6 class IntField:
 7     def __get__(self, instance, owner):
 8         return self.value
 9 
10     def __set__(self, instance, value):
11         if not isinstance(value, numbers.Integral):
12             raise ValueError('int value need')
13         if value < 0:
14             raise ValueError('positive value need')
15         self.value = value
16 
17     def __delete__(self, instance):
18         pass
19 
20 
21 class NotDataIntField:
22     def __get__(self, instance, owner):
23         return self.value
24 
25 
26 class User:
27     age = NotDataIntField()
28 
29 
30 if __name__ == '__main__':
31     user = User()
32     User.age = 30
33     User.z = 10
34     print(User.__dict__)
35     print(user.__dict__)
36     print(User.age)
37     print(user.age)
38 
39     # ValueError('int value need')
40     # user.age = 'z'
41     # print(user.age)
42 
43     # ValueError('positive value need')
44     # user.age = -1
45     # print(user.age)
{'__module__': '__main__', 'age': 30, '__dict__': <attribute '__dict__' of 'User' objects>, '__weakref__': <attribute '__weakref__' of 'User' objects>, '__doc__': None, 'z': 10}
{}
30
30

  

原文地址:https://www.cnblogs.com/zydeboke/p/11265485.html