這裡引用一段代碼來試圖說明我對描述符的了解
class A(): #定義關于攝氏度的描述符
def __init__(self,value = 30.0):
self.value = float(value)
def __get__(self,instance,owner):
return self.value
def __set__(self,instance,value):
self.value = float(value)
class B(): #定義關于華氏度的描述符
def __get__(self,instance,owner): #攝氏度轉華氏度
return instance.cel*1.8+32
def __set__(self,instance,value): #華氏度轉攝氏度
instance.cel = (float(value)-32)/1.8
class T():
cel = A()
har = B() #定義攝氏度屬性cel與華氏度屬性har
#運作結果如下
In[]: a = T()
In[]: a.cel
Out[]: 30.0
In[]: a.har
Out[]: 86.0
In[]: a.har = 70
In[]: a.cel
Out[]: 21.11111111111111
首先明确描述符的定義:
描述符就是一個具有綁定行為的對象屬性,其屬性通路将由描述符協定中的方法覆寫。這些方法為__get__、set__和__delete。如果這些方法中的任何一個針對某個對象定義,那麼它就被認為是一個描述符
__get__方法是指目前屬性的值被取得時則調用該方法
__set__方法是指目前屬性的值被修改時則調用該方法
__delete__方法是指目前屬性的值被删除時則調用該方法
參數instance表示目前執行個體化對象
參數owner表示目前執行個體化對象所屬的類
來看代碼
當使用a來執行個體化T類時,此時a内已經含有cel屬性
a=T()
a.cel = 30
因為在a執行個體化T類時,首先自動調用了 A() 類内的__init__()方法,此時已經傳值給value,使得a.cel得到value的值為30。
指令行調用a.har屬性,傳回得到86.0
In[] : a.har
Out[] : 86.0
def __get__(self,instance,owner): #B類中__get__方法 屬性值被取得時調用
return instance.cel*1.8+32
這裡是因為使用a.har時,自動調用了B類中的__get__()方法,則取得a.har的值
此處函數中的instance參數就是指目前執行個體a,傳回值即是a.cel參與運算的運算結果,即是調用a.har的結果
In[]:a.har = 70
In[]:a.cel
Out[]:21.11111111111
此處修改屬性a.har的值,再檢視a.cel屬性的值,發現随之改變
def __set__(self,instance,value): #B類中的__set__方法 屬性值被修改時調用
instance.cel = (float(value)-32)/1.8
def __get__(self,instance,owner): #A類中的__get__方法 屬性值被取得時調用
return self.value
a.har = 70這句語句觸發時,辨別執行個體化對象a的屬性har值被修改,則此時自動調用har依托的B類中的__set__方法,此時傳入函數的參數instance=執行個體化對象a,value = 70,進行将(70-32)/1.8 的結果指派給a.cel的操作。
而給a.cel指派,即調用了cel依托的A類中__set__方法并傳入參數value = (70-32)/1.8 ,使得函數内self.value = (70-32)/1.8。
再次檢視a.cel的值,則調用cel依托A類中的__get__方法傳回目前cel屬性的值,即為上指派給該屬性的(70-32)/1.8。
解釋代碼過程我使用了‘依托’這個詞來表示屬性與描述符之間的關系,實際上并不能這麼了解,但是能力有限,也隻能這樣描述了。
整個代碼過程相當于,使用a來對T類進行執行個體化時,在T類内含有屬性cel與屬性har,則執行個體化對象a含有cel與har兩屬性。通過cel = A()語句來實作cel與A類描述符的相關聯,屬性har同理。此時對兩屬性進行重寫函數的操作時,則會自動調用你重寫的相關操作的方法
第一次寫這種部落格,描述能力實在有限,大家願意看下去的我在這裡多謝了。如果了解有什麼問題也歡迎大家評論區提出來或者留言,感謝感謝