import numbers
'''
如果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’], 否则
(3)如果“age”出现在User或其基类的__dict__中
(3.1)如果age是non-data descriptor,那么调用其__get__方法, 否则
(3.2)返回 __dict__[‘age’]
(4)如果User有__getattr__方法,调用__getattr__方法,否则
(5)抛出AttributeError
'''
class IntField:
"""数据描述符"""
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
if isinstance(value,numbers.Integral):
self.value = value
else:
raise ValueError
def __delete__(self, instance):
pass
class NotIntField:
"""非数据描述"""
def __get__(self, instance, owner):
return 31
class User:
age = IntField()
# age = NotIntField()
def __init__(self,name,weight):
self.name = name
self.weight = weight
user = User("zhou",34)
user.age = 10
print(user.__dict__)
print("User.__dict__: ", User.__dict__)
print("IntField.__dict__: ", IntField.__dict__)
print(user.age)
{'name': 'zhou', 'weight': 34}
User.__dict__: {'__doc__': None, '__weakref__': <attribute '__weakref__' of 'User' objects>, '__module__': '__main__', 'age': <__main__.IntField object at 0x0000000004D11470>, '__init__': <function User.__init__ at 0x0000000004D7C268>, '__dict__': <attribute '__dict__' of 'User' objects>}
IntField.__dict__: {'__set__': <function IntField.__set__ at 0x0000000004D7C158>, '__get__': <function IntField.__get__ at 0x0000000004D7CD90>, '__doc__': '数据描述符', '__weakref__': <attribute '__weakref__' of 'IntField' objects>, '__module__': '__main__', '__delete__': <function IntField.__delete__ at 0x0000000004D7CE18>, '__dict__': <attribute '__dict__' of 'IntField' objects>}
10
user.age=10 就是调用了age的IntField实例中的set方法
输出 user.age:
1 age 出现在User的dict中,而且age是数据描述符,所以调用IntField实例的get方法
class User:
age = IntField()
# age = NotIntField()
def __init__(self,name,weight):
self.name = name
self.weight = weight
user = User("zhou",34)
user.__dict__["age"] = "ab"
print(user.__dict__["age"])
print("user.__dict__: ", user.__dict__)
print("User.__dict__: ", User.__dict__)
print("IntField.__dict__: ", IntField.__dict__)
print(user.age)
ab
user.__dict__: {'name': 'zhou', 'age': 'ab', 'weight': 34}
User.__dict__: {'__doc__': None, '__weakref__': <attribute '__weakref__' of 'User' objects>, '__module__': '__main__', 'age': <__main__.IntField object at 0x0000000004D913C8>, '__init__': <function User.__init__ at 0x0000000004D7CF28>, '__dict__': <attribute '__dict__' of 'User' objects>}
IntField.__dict__: {'__set__': <function IntField.__set__ at 0x0000000004D7C158>, '__get__': <function IntField.__get__ at 0x0000000004D7CD90>, '__doc__': '数据描述符', '__weakref__': <attribute '__weakref__' of 'IntField' objects>, '__module__': '__main__', '__delete__': <function IntField.__delete__ at 0x0000000004D7CE18>, '__dict__': <attribute '__dict__' of 'IntField' objects>}
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-12-621de20b36d7> in <module>()
14 print("User.__dict__: ", User.__dict__)
15 print("IntField.__dict__: ", IntField.__dict__)
---> 16 print(user.age)
<ipython-input-11-efe384b96662> in __get__(self, instance, owner)
25 """数据描述符"""
26 def __get__(self, instance, owner):
---> 27 return self.value
28
29 def __set__(self, instance, value):
AttributeError: 'IntField' object has no attribute 'value'
user.dict["age"] = "ab",没有调用set方法,所以不会存在self.value
输出 user.age:
1 age 出现在User的dict中,而且age是数据描述符,所以调用IntField实例的get方法 ,因为没有执行 set方法,所以不会存在self.value;报错
class User:
# age = IntField()
age = NotIntField()
def __init__(self,name,weight):
self.name = name
self.weight = weight
user = User("zhou",34)
user.age = 10
print(user.__dict__)
print(IntField.__dict__)
print(user.age)
{'name': 'zhou', 'age': 10, 'weight': 34}
{'__set__': <function IntField.__set__ at 0x0000000004D7C158>, '__get__': <function IntField.__get__ at 0x0000000004D7CD90>, '__doc__': '数据描述符', '__weakref__': <attribute '__weakref__' of 'IntField' objects>, '__module__': '__main__', '__delete__': <function IntField.__delete__ at 0x0000000004D7CE18>, '__dict__': <attribute '__dict__' of 'IntField' objects>}
10
输出 user.age:
1 age 出现在User的dict中,但是age不是数据描述符,所以往下找;
2 “age”出现在user的dict中, 那么直接返回 obj.dict[‘age’],