from datetime import date, datetime import numbers class IntField: # 数据描述符 def __get__(self, instance, owner): return self.value def __set__(self, instance, value): if not isinstance(value, numbers.Integral): raise ValueError("int value need") if value < 0: raise ValueError("positive value need") self.value = value def __delete__(self, instance): pass class NonDataIntField: # 非数据属性描述符 def __get__(self, instance, owner): return self.value class User: age = IntField() # 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”出现在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 User: # # def __init__(self, name, email, birthday): # self.name = name # self.email = email # self.birthday = birthday # self._age = 0 # # # def get_age(self): # # return datetime.now().year - self.birthday.year # # @property # def age(self): # return datetime.now().year - self.birthday.year # # @age.setter # def age(self, value): # #检查是否是字符串类型 # self._age = value if __name__ == "__main__": user = User() user.__dict__["age"] = "abc" print(user.__dict__) print(user.age) # print (getattr(user, 'age')) # user = User("bobby", date(year=1987, month=1, day=1)) # user.age = 30 # print (user._age) # print(user.age)
只要是类中实现任一个__get__,__set__ ,__delete__方法中的任意一个方法,他都是属性描述符的对象,
通过属性描述符就可以控制赋值的属性。
数据属性描述符和非数据属性描述符的区别:
1,数据属性描述符实现三个方法,但是非数据属性描述符仅实现__get__
2,在类中且属于属性描述符,优先调用