1. 程式人生 > >屬性描述符和屬性的查詢過程

屬性描述符和屬性的查詢過程

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,在類中且屬於屬性描述符,優先呼叫