Python3學習(24)--內建裝飾器@property
@property
前面我們學過裝飾器,我們知道,裝飾器的作用就是用來擴充套件函式的,當然前面我們介紹的裝飾器,都是我們自己定義的,格式如下:
@decoretor
def func(*args,**others)
pass
func(.....) #使用裝飾過的函式
而我們今天講的這個裝飾器@property,屬於Python內建的一個裝飾器,廣泛應用於類的定義中的,從字面意思上理解,是屬性的意思,我們想到了類,類中例項的屬性,我們講過,例項的屬性是可以隨意繫結的(當然也可以通過__slots__變數限制例項屬性的繫結),這就意味著,例項的屬性是完全暴露的,這種暴露性,導致屬性可以任意被修改,比如下面一個簡單的例子:
property.py:
#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-
class Student(object):
pass
s = Student()
s.score=90
print(s.score)
s.score=188
print(s.score)
我們給Student類的例項s綁定了一個score屬性變數,我們知道,這個變量表示一個學生單科的成績,當然,據我們所知,成績應該是不能超過100的(根據滿分制100分來),但是,上述的demo我們可以看到,通過例項物件s我們可以隨意的修改score的值,哪怕它超過了100分,我們也可以將這個不合理的成績打印出來:
如果,我們想要控制這種不合理成績的輸出,我們可以在外部繫結屬性值的時候,做條件判斷,當然,我們也可以在類Student的內部,通過增加兩個函式,set_xxx和get_xxx分別來控制屬性score的值的輸入和返回,因此,我們修改下上述程式碼:
#!/usr/bin/env Python3 # -*- encoding:UTF-8 -*- class Student(object): def set_score(self,value): if value>=0 and value <= 100: self.__score = value #還記得__score嗎?前面加一個雙下劃線,表示private私有屬性 else: raise ValueError('score must between 0 ~ 100!') def get_score(self): return self.__score s = Student() s.set_score(90) print(s.get_score()) s.set_score(188) print(s.get_score())
當我們set成績等於90的時候,符合類內部定義的函式set_score的條件,當然,設定188的時候,由於超過100了,因此,我們會看到下面的輸出:
這樣一來,我們就可以到達我們想要的效果,在錄入成績的時候,可以對我們的成績score的值進行檢查判斷,從而保證資料的合法性,當然,Python是追求精簡的,哪怕少寫一對括號,我們的Python也要實現它,這就不得不說我們今天講的@property了,我們先看下面一段程式碼:
#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-
class Student(object):
@property
def score(self):
return self.__score
@score.setter
def score(self,value):
if value>=0 and value <= 100:
self.__score = value #還記得__score嗎?前面加一個雙下劃線,表示private私有屬性
else:
raise ValueError('score must between 0 ~ 100!')
s = Student()
s.score = 90
print(s.score)
@property 修飾函式score(getter),將score函式變成score屬性輸出,此外,@property 本身又建立了另一個裝飾器@score.setter,負責把一個 setter 函式變成屬性賦值,於是,我們雖然看到了類Student內部定義了兩個函式score,對,沒錯,都是score,但是,他們卻被不同的裝飾器裝飾,getter函式被@property修飾,setter函式被@property建立的函式的setter裝飾器@score.setter修飾,因此,我們可以直接用s.score=90來代替s.set_socre(90),達到給score屬性賦值的效果,簡單粗暴,精益求精,雖然實現的效果一樣,但是寫起來,還是直接s.score=90來的更舒坦一些,我們驗證下執行結果:
當然,我們上面建立了@property另一個裝飾器函式@xxx.setter,對私有屬性__score進行輸入值的判斷,如果,我們不建立裝飾器@xxx.setter可以嗎?如果不建立的話,屬性xxx就是一個只讀屬性,意味著不能被修改,下面我們先來看一個普通的只讀屬性函式:
#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-
class Student(object):
@property
def score(self):
return self.__score
@score.setter
def score(self,value):
if value>=0 and value <= 100:
self.__score = value #還記得__score嗎?前面加一個雙下劃線,表示private私有屬性
else:
raise ValueError('score must between 0 ~ 100!')
def age(self):
self.__age = 26
return self.__age
s = Student()
s.score = 90
print(s.score)
print(s.age())
我們在類中又定義了一個age 函式,該函式返回一個定值,26,如果我們想要,獲得私有屬性__age的值26,我們必須呼叫age()函式:
當然,如果我們直接呼叫s.age,不會報錯,而會輸出函式age的函式地址:
通過本篇所學,我們可以給age函式增加一個@property裝飾器,達到直接呼叫s.age輸出我們要的26,因此,我們改下上述demo:
#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-
class Student(object):
@property
def age(self): #將getter函式轉變為屬性age直接輸出
self.__age = 26
return self.__age
s = Student()
print(s.age)
我們看下輸出:
ok,我們的@property發揮奇效,我們說了,我們沒有新增@xxx.setter裝飾器,因此,age是一個只讀屬性,如果我們試圖修改age的值,我們看下效果,是不是可行?
如果,想要這個age既可以讀也可以寫,我們可以這樣做:
好了,通過本篇的講解,我們應該知道@property的用途了吧,它可以讓呼叫者寫出簡短的程式碼,同時保證對引數進行必要的檢查,這樣,程式執行時就減少了出錯的可能性。