python3:屬性描述符(__get__,__set__,__delete__)

我先問大家個問題。

如何對屬性進行校驗呢 比如有個要保證 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)

解釋下

  1. 首先我們要把共同的校驗封裝在一個類裏也就是 Int_validation 類,
  2. 重寫兩個魔法函數 (get 和set)
  3. age=Int_validation() 這個是關鍵,age 本來是個對象,放在類裏當作了Student類屬性
  4. 實例化對象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 方法,這也是魔法函數的特性 。
有不明白的或者錯誤的請聯繫我,或者在下邊評論 ,謝謝

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章