Python类中属性查找过程:
from datetime import date,datetime
import numbers
class IntField: # 此处的类如何变成属性描述符?只需要实现get方法,或者是set方法,类里面的任一个方法 都是属性描述符,可以用于后续规则的检查
# IntField实现对Int类型的检查
def __get__(self,instance,owner):
return self.value # __set__中定义了value参数,此处返回,需要确保前后一致,因此未self.value
def __set__(self,instance,value): # 赋值/set的时候,进行了参数类型的检查
if not isinstance(value,numbers.Integral):
raise ValueError("int value required")
self.value = value # 将传进来的value赋给IntFiled这个class中
def __delete__(self,instance):
pass
class User:
age = IntField() # 实际数据库中,不会存储age这个字段,age通过自动计算获取;类实例化,传给age
# age只要实现__get__/__set__/__delete__三个方法中的任一个方法,就是属性描述符
# 此处,age会调用IntField的__set__方法
if __name__ == "__main__":
user = User()
# 通过属性描述符,实现了对赋值时候的行为的控制
# user.age = "abc" # 此处会报错,提示 raise ValueError("int value required"),ValueError: int value required
user.age = 18 # 此处给属性描述符赋值时,实际上会调用set方法
print(user.age) # 18
from datetime import date,datetime
import numbers
class IntField: # 此处的类如何变成属性描述符?只需要实现get方法,或者是set方法,类里面的任一个方法 都是属性描述符,可以用于后续规则的检查
# IntField实现对Int类型的检查
def __get__(self,instance,owner):
return self.value # __set__中定义了value参数,此处返回,需要确保前后一致,因此未self.value
def __set__(self,instance,value): # 赋值/set的时候,进行了参数类型的检查
if not isinstance(value,numbers.Integral):
raise ValueError("int value required")
if value < 0:
raise ValueError("positive value required")
self.value = value # 将传进来的value赋给IntFiled这个class中
def __delete__(self,instance):
pass
class User:
age = IntField() # 实际数据库中,不会存储age这个字段,age通过自动计算获取;类实例化,传给age
# age只要实现__get__/__set__/__delete__三个方法中的任一个方法,就是属性描述符
# 此处,age会调用IntField的__set__方法
if __name__ == "__main__":
user = User()
# 通过属性描述符,实现了对赋值时候的行为的控制
# user.age = "abc" # 此处会报错,提示 raise ValueError("int value required"),ValueError: int value required
user.age = -18 # 此处给属性描述符赋值时,实际上会调用set方法
print(user.age) # 18
Traceback (most recent call last):
File "C:/Users/Amber/PycharmProjects/test0/Chapter08/attr_desc.py", line 28, in
user.age = -18 # 此处给属性描述符赋值时,实际上会调用set方法
File "C:/Users/Amber/PycharmProjects/test0/Chapter08/attr_desc.py", line 13, in __set__
raise ValueError("positive value required")
ValueError: positive value required
在属性描述符中,__get__/__set__/__delete__三个方法中的任意实现一个,就可以把它当作为属性描述符。
实际上,属性描述符包括两种,一:实现了__get__/__set__,数据描述符;二:非数据属性描述符,比如只实现get方法
属性查找过程:一般,先查找实例属性,然后查找类属性
from datetime import date,datetime
import numbers
class IntField:
# 数据描述符
# 此处的类如何变成属性描述符?只需要实现get方法,或者是set方法,类里面的任一个方法 都是属性描述符,可以用于后续规则的检查
# IntField实现对Int类型的检查
def __get__(self,instance,owner):
return self.value # __set__中定义了value参数,此处返回,需要确保前后一致,因此未self.value
def __set__(self,instance,value): # 赋值/set的时候,进行了参数类型的检查
if not isinstance(value,numbers.Integral):
raise ValueError("int value required")
if value < 0:
raise ValueError("positive value required")
self.value = value # 将传进来的value赋给IntFiled这个class中
def __delete__(self,instance):
pass
class NonDataIntField:
# 非数据属性描述符
def __get__(self,instance,owner):
pass
class User:
age = IntField() # 实际数据库中,不会存储age这个字段,age通过自动计算获取;类实例化,传给age
# age只要实现__get__/__set__/__delete__三个方法中的任一个方法,就是属性描述符
# 此处,age会调用IntField的__set__方法
'''
如果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”是出现在obj(对象)的__dict__中,那么直接返回obj.__dict__['age'],否则
3- 如果“age”是出现在User或其基类的__dict__中,且age是data descriptor, 那么调用其
- 3.1: 如果age是non-data descriptor,那么调用其__get__方法,否则
- 3.2: 返回__dict__['age']
4- 如果User有__getattr__方法,调用__getattr__方法,否则(如果查找不到)
5- 抛出AttributeError
'''
if __name__ == "__main__":
user = User()
# 通过属性描述符,实现了对赋值时候的行为的控制
# user.age = "abc" # 此处会报错,提示 raise ValueError("int value required"),ValueError: int value required
user.age = 18 # 此处给属性描述符赋值时,实际上会调用set方法
print(user.__dict__) # {}
print(user.age) # 18
上例,倒数第二句,print(user.__dict__) 输出为空字典,并没有出现在对象中,因为此时优先调用数据描述符,此时会优先进入IntField中的value中,并没有进入user这个实例中。
from datetime import date,datetime
import numbers
class IntField:
# 数据描述符
# 此处的类如何变成属性描述符?只需要实现get方法,或者是set方法,类里面的任一个方法 都是属性描述符,可以用于后续规则的检查
# IntField实现对Int类型的检查
def __get__(self,instance,owner):
return self.value # __set__中定义了value参数,此处返回,需要确保前后一致,因此未self.value
def __set__(self,instance,value): # 赋值/set的时候,进行了参数类型的检查
if not isinstance(value,numbers.Integral):
raise ValueError("int value required")
if value < 0:
raise ValueError("positive value required")
self.value = value # 将传进来的value赋给IntFiled这个class中
def __delete__(self,instance):
pass
class NonDataIntField:
# 非数据属性描述符
def __get__(self,instance,owner):
pass
class User:
# age = IntField() # 实际数据库中,不会存储age这个字段,age通过自动计算获取;类实例化,传给age
# age只要实现__get__/__set__/__delete__三个方法中的任一个方法,就是属性描述符
# 此处,age会调用IntField的__set__方法
age = NonDataIntField()
'''
如果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”是出现在obj(对象)的__dict__中,那么直接返回obj.__dict__['age'],否则
3- 如果“age”是出现在User或其基类的__dict__中,且age是data descriptor, 那么调用其
- 3.1: 如果age是non-data descriptor,那么调用其__get__方法,否则
- 3.2: 返回__dict__['age']
4- 如果User有__getattr__方法,调用__getattr__方法,否则(如果查找不到)
5- 抛出AttributeError
'''
if __name__ == "__main__":
user = User()
# 通过属性描述符,实现了对赋值时候的行为的控制
# user.age = "abc" # 此处会报错,提示 raise ValueError("int value required"),ValueError: int value required
user.age = 18 # 此处给属性描述符赋值时,实际上会调用set方法
print(user.__dict__) # {'age': 18}
print(user.age) # 18
上例,第27行,注释掉 # age = IntField(),第30行,定义age = NonDataIntField(), 则倒数第二句,print(user.__dict__) 输出为{'age': 18},有出现在对象中
from datetime import date,datetime
import numbers
class IntField:
# 数据描述符
# 此处的类如何变成属性描述符?只需要实现get方法,或者是set方法,类里面的任一个方法 都是属性描述符,可以用于后续规则的检查
# IntField实现对Int类型的检查
def __get__(self,instance,owner):
return self.value # __set__中定义了value参数,此处返回,需要确保前后一致,因此未self.value
def __set__(self,instance,value): # 赋值/set的时候,进行了参数类型的检查
if not isinstance(value,numbers.Integral):
raise ValueError("int value required")
if value < 0:
raise ValueError("positive value required")
self.value = value # 将传进来的value赋给IntFiled这个class中
def __delete__(self,instance):
pass
class NonDataIntField:
# 非数据属性描述符
def __get__(self,instance,owner):
pass
class User:
age = IntField() # 实际数据库中,不会存储age这个字段,age通过自动计算获取;类实例化,传给age
# age只要实现__get__/__set__/__delete__三个方法中的任一个方法,就是属性描述符
# 此处,age会调用IntField的__set__方法
# age = NonDataIntField()
'''
如果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”是出现在obj(对象)的__dict__中,那么直接返回obj.__dict__['age'],否则
3- 如果“age”是出现在User或其基类的__dict__中,且age是data descriptor, 那么调用其
- 3.1: 如果age是non-data descriptor,那么调用其__get__方法,否则
- 3.2: 返回__dict__['age']
4- 如果User有__getattr__方法,调用__getattr__方法,否则(如果查找不到)
5- 抛出AttributeError
'''
if __name__ == "__main__":
user = User()
# 通过属性描述符,实现了对赋值时候的行为的控制
# user.age = "abc" # 此处会报错,提示 raise ValueError("int value required"),ValueError: int value required
user.__dict__["age"] = "abc"
#user.age = 18 # 此处给属性描述符赋值时,实际上会调用set方法
print(user.__dict__) # {'age': 'abc'}
print(user.age) # AttributeError: 'IntField' object has no attribute 'value'
如果第27行还是数据描述符,age = IntField(), 第30行注释掉# age = NonDataIntField(),新增59行user.__dict__["age"] = "abc",注释掉#user.age = 18,此时61行print(user.__dict__) 输出为{'age': 'abc'}。发现age在__dic__中
第62行,print(user.age) # AttributeError: 'IntField' object has no attribute 'value' 抛出异常。因为int类型并没有vale这个属性。
虽然59行,user.__dict__["age"] = "abc" user.age放在属性中,执行user.age时,还是按照顺序查找,抛出异常。除非采用如下方式:print(user.__dict__["age"]) # abc
from datetime import date,datetime
import numbers
class IntField:
# 数据描述符
# 此处的类如何变成属性描述符?只需要实现get方法,或者是set方法,类里面的任一个方法 都是属性描述符,可以用于后续规则的检查
# IntField实现对Int类型的检查
def __get__(self,instance,owner):
return self.value # __set__中定义了value参数,此处返回,需要确保前后一致,因此未self.value
def __set__(self,instance,value): # 赋值/set的时候,进行了参数类型的检查
if not isinstance(value,numbers.Integral):
raise ValueError("int value required")
if value < 0:
raise ValueError("positive value required")
self.value = value # 将传进来的value赋给IntFiled这个class中
def __delete__(self,instance):
pass
class NonDataIntField:
# 非数据属性描述符
def __get__(self,instance,owner):
pass
class User:
age = IntField() # 实际数据库中,不会存储age这个字段,age通过自动计算获取;类实例化,传给age
# age只要实现__get__/__set__/__delete__三个方法中的任一个方法,就是属性描述符
# 此处,age会调用IntField的__set__方法
# age = NonDataIntField()
'''
如果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”是出现在obj(对象)的__dict__中,那么直接返回obj.__dict__['age'],否则
3- 如果“age”是出现在User或其基类的__dict__中,且age是data descriptor, 那么调用其
- 3.1: 如果age是non-data descriptor,那么调用其__get__方法,否则
- 3.2: 返回__dict__['age']
4- 如果User有__getattr__方法,调用__getattr__方法,否则(如果查找不到)
5- 抛出AttributeError
'''
if __name__ == "__main__":
user = User()
# 通过属性描述符,实现了对赋值时候的行为的控制
# user.age = "abc" # 此处会报错,提示 raise ValueError("int value required"),ValueError: int value required
user.__dict__["age"] = "abc"
#user.age = 18 # 此处给属性描述符赋值时,实际上会调用set方法
print(user.__dict__) # {'age': 'abc'}
print(user.__dict__["age"]) # abc
__dict__ 属性属于user这个对象。
使用user.__dict__实际上是查找的__dict__属性,而不是age属性。查找与对象user无关
作者:世界非世界,是名世界!