原文:https://zhuanlan.zhihu.com/p/32764345html
# 相似函數的形式 class A: def __init__(self, name, score): self.name = name # 普通屬性 self.score = score def getscore(self): return self._score def setscore(self, value): print('setting score here') if isinstance(value, int): self._score = value else: print('please input an int') score = property(getscore, setscore) a = A('Bob',90) a.name # 'Bob' a.score # 90 a.score = 'bob' # please input an int
分析上述調用score的過程python
property(getscore, setscore)
對象,由於後者中定義了__get__
與__set__
方法,所以是一個資料描述器,具備比屬性更高的優先級,因此這裏就訪問了描述器__set__
方法__set__
中對fset
屬性進行檢查,這裏即傳入的setscore
,不是None
,因此調用了fset
即setscore
方法,這就實現了設置屬性時使用自定義函數進行檢查的目的__get__
也是同樣,查詢score時,調用__get__
方法,觸發了getscore
方法下面是另外一種使用property的方法緩存
# 裝飾器形式,即引言中的形式 class A: def __init__(self, name, score): self.name = name # 普通屬性 self.score = score @property def score(self): print('getting score here') return self._score @score.setter def score(self, value): print('setting score here') if isinstance(value, int): self._score = value else: print('please input an int') a = A('Bob',90) # a.name # 'Bob' # a.score # 90 # a.score = 'bob' # please input an int
下面進行分析框架
score
時,加上裝飾器變成訪問property(score)
這個描述器,這個score
也做爲fget
參數傳入__get__
中指定調用時的操做setter
等方法的定義property
和setter
裝飾器的兩個方法的命名都仍是score,通常同名的方法後面的會覆蓋前面的,因此調用時調用的是後面的setter
裝飾器處理過的score
,是以若是兩個裝飾器定義的位置調換,將沒法進行屬性賦值操做。setter
裝飾器的score
時,面臨一個問題,裝飾器score.setter
是什麼呢?是score
的setter
方法,而score
是什麼呢,不是下面定義的這個score
,由於那個score
只至關於參數傳入。自動向其餘位置尋找有沒有現成的score
,發現了一個,是property
修飾過的score
,這是個描述器,根據property
的定義,裏面確實有一個setter
方法,返回的是property
類傳入fset
後的結果,仍是一個描述器,這個描述器傳入了fget
和fset
,這就是最新的score
了,之後實例只要調用或修改score
,使用的都是這個描述器del
則裝飾器中的score
找到的是setter
處理過的score
,最新的score
就會是三個函數都傳入的score
score
的調用及賦值刪除都跟前面同樣了property
的原理就講到這裏,從它的定義咱們能夠知道它其實就是將咱們設置的檢查等函數傳入get set
等方法中,讓咱們能夠自由對屬性進行操做。它是一個框架,讓咱們能夠方便傳入其餘操做,當不少對象都要進行相同操做的話,重複就是不免的。若是想要避免重複,只有本身寫一個相似property
的框架,這個框架不是傳入咱們但願的操做了,而是就把這些操做放在框架裏面,這個框架由於只能實現一種操做而不具備普適性,可是卻能大大減小當前問題代碼重複問題ide
下面使用描述器定義了Checkint類以後,會發現A類簡潔了很是多函數
class Checkint: def __init__(self, name): self.name = name def __get__(self, instance, owner): if instance is None: return self else: return instance.__dict__[self.name] def __set__(self, instance, value): if isinstance(value, int): instance.__dict__[self.name] = value else: print('please input an integer') # 相似函數的形式 class A: score = Checkint('score') age = Checkint('age') def __init__(self, name, score, age): self.name = name # 普通屬性 self.score = score self.age = age a = A('Bob', 90, 30) a.name # 'Bob' a.score # 90 # a.score = 'bob' # please input an int # a.age='a' # please input an integer
由於我本人也剛剛學描述器不久,對它的應用還不是很是瞭解,下面只列舉我如今能想到的它有什麼用,之後若是想到其餘的再補充ui
__get__
方法中,在判斷語句下,obj.__dict__[self.name] = value
。這樣每次再調用這個方法都會從這個字典中取得值,而不是從新運行這個方法。(例子來源最後的那個例子)參考網頁以下spa