1. 程式人生 > >python之屬性描述符與屬性查詢規則

python之屬性描述符與屬性查詢規則

描述符
import numbers
class IntgerField:
    def __get__(self, isinstance, owner):
        print('獲取age')
        return self.num
    
    def __set__(self, instance, value):
        print('設定age值時')
        if  not isinstance(value, numbers.Integral):
            raise ValueError('int need')
        self.num = value
    def __delete__(self, instance):
        pass


class User:
    age = IntgerField()   // 資料屬性描述符,查詢優先順序最高


user = User()
user.age = 33
print(user.age)


上述的User可以看做資料庫中的表,假設我們要控制user中age的賦值型別,固然可以使用以下形式進行攔截:

class User:
    age = 33
    def __setattr__(self, name, value):
        pass               // 這裡進行型別檢測
又或者:
class User:
    @property
    def age(self):
        return self._num
    @age.setter
    def age(self,value):
        self._num = value // 這裡進行型別檢測

但是這種一兩次還行,多了就是在寫重複程式碼,所以就可用上述類IntgerField中定義__get__,__set__等實現屬性描述符的方式進行攔截。
getattributegetattrsetattr、__delattr__等方法用來實現屬性查詢、設定、刪除的一般邏輯,而對屬性的控制行為就由屬性物件來控制。這裡單獨抽離出來一個屬性物件,在屬性物件中定義這個屬性的查詢、設定、刪除行為。這個屬性物件就是描述符。
描述符物件一般是作為其他類物件的屬性而存在。在其內部定義了三個方法用來實現屬性物件的查詢、設定、刪除行為。這三個方法分別是:
get(self, instance, owner):定義當試圖取出描述符的值時的行為。
set(self, instance, value):定義當描述符的值改變時的行為。
delete(self, instance):定義當描述符的值被刪除時的行為。
其中:instance為把描述符物件作為屬性的物件例項;
owner為instance的類物件。

描述符有資料描述符和非資料描述符之分

只要至少實現__get__、set、__delete__方法中的一個就可以認為是描述符;
只實現__get__方法的物件是非資料描述符,意味著在初始化之後它們只能被讀取;
同時實現__get__和__set__的物件是資料描述符,意味著這種屬性是可讀寫的。

屬性查詢規則

當查詢物件上的某個屬性時,假設是user.age,順序先是判斷該例項所指向的類以及基類的__dict__中查詢,並且如果該屬性資料屬性描述符,就會呼叫描述符中的__get__方法
如果該age直接出現在obj.__dict__上,直接返回obj.__dict__['age']
如果該屬性出現在User中或基類中,且該屬性是非資料屬性描述符,就會呼叫其__get__方法,如果不是非資料屬性描述符,就會呼叫User或基類的User或基類.__dict__['age']
如果這些都沒有,且User上也沒有__getattr__方法,就會報錯