python3:屬性描述符(__get__,__set__,__delete__)
阿新 • • 發佈:2018-11-09
我先問大家個問題。
如何對屬性進行校驗呢 比如有個要保證 age 屬性 它只能是int型別且大小處於0到100之間?
第一直覺就是用get 和set 方法如下:
1.基本的呼叫 set 和get 方法
class Student: def __init__(self): pass def get(self): return self.age def set(self,age): if isinstance(age,int) and 0<age<100: self.age=age else: print("請輸入合法的年齡") stu=Student() stu.set(110) #請輸入合法的年齡 stu.set(10) print(stu.get()) #10
有的小夥伴該說了,你這太低階了,現在都是用property 了
2.利用@property
對,正確的做法就是 用**@property 裝飾器**,可以把方法封裝成
屬性。
例如:
class Student: def __init__(self): pass @property def age(self): return self.value @age.setter def age(self,value): if isinstance(value,int) and 0<value<100: self.value=value else: print("請輸入合法的年齡") stu=Student() stu.age=10 print(stu.age) # 10
恭喜你明白了@property 的用法。前面都是引子,現在開始我們的正題。
現在又有一個場景:
像age屬性 一共有十幾個,你該如何做呢
用@property 是可以做到,你知道你需要寫多少方法嗎,得寫20多個,
這程式碼量也實在太大了吧,這個難道不了我們的優秀的高階開發測試員。
3.利用屬性描述符
屬性描述符的原理利用的是抽象的方法, 把十幾個欄位共同的特性抽出來,
每個欄位都用這個特性,達到節省程式碼的目的。 看下 下邊的例子:
class Int_validation: def __get__(self, instance, owner): return self.value def __set__(self, instance, value): if isinstance(value,int) and 0<value<100: self.value=value #這個要注意 要用value,不能用instance 否則會陷入死迴圈 else: print("請輸入合法的數字") def __delete__(self, instance): pass class Student: age=Int_validation() stu=Student() stu.age=50 print(stu.age)
解釋下
- 首先我們要把共同的校驗封裝在一個類裡也就是 Int_validation 類,
- 重寫兩個魔法函式 (get 和set)
- age=Int_validation() 這個是關鍵,age 本來是個物件,放在類裡當作了Student類屬性
- 例項化物件stu給age進行賦值 ,它會自動呼叫Int_validation get的方法 ,我們debug get方法看下過程
value = {int} 50
self = {Int_validation} <__main__.Int_validation object at 0x0000025AA8362CC0>
instance = {Student} <__main__.Student object at 0x0000025AA8362CF8>
顯然會把 50 給value, self 就是age本身, instance就是stu
這就是為什麼不能 self.instance=instance,而是 self.value=value ,
它會再走一次流程進入死迴圈。
value=50 進入校驗流程 。
5. 當我們呼叫了 stu.age ,它會呼叫get方法 並返回值。
debug 的程式碼
instance = {Student} <__main__.Student object at 0x000001883B6F2CF8>
self = {Int_validation} <__main__.Int_validation object at 0x000001883B6F2CC0>
總結:
1.其他屬性也可以用age 方式,自己可以試試
2.這裡面 有屬性描述符的三要素 要掌握並理解它們的含義, (value,instance,self)缺一不可。
3.巧妙的利用了三個魔法函式,正好 校驗類物件是應用類的屬性,並且你們會發現我們並沒有
呼叫set和get 方法,這也是魔法函式的特性 。
有不明白的或者錯誤的請聯絡我,或者在下邊評論 ,謝謝