問題引出
在業務處理時經常需要在數據的讀取和存入前對數據進行預處理,通過@property和@*.setter兩個裝飾器就可以方便的實現。
@property
python中的@property裝飾器可以總結為兩個作用:
- 讓函數可以像普通變量一樣使用
- 對要讀取的數據進行預處理
示例1
我們先編寫一個測試類:
class User(): def __init__(self, name, age): self.name = name self.age = age
假設現在我們需要將name與age合並成一個新屬性tag,在不使用@property和修改類屬性的情況下我們可能會這樣寫:
class User(): def __init__(self, name, age): self.name = name self.age = age def tag(self): return self.name + str(self.age) user = User('xiao',5) print(user.tag())
這種方式自然沒有問題,但是tag與其說是一個函數其實更像是user對象的一個屬性,用user.tag()的方法獲取顯得不那么自然,而使用@property裝飾器我們就可以用user屬性的方式來得到tag:
class User(): def __init__(self, name, age): self.name = name self.age = age @property def tag(self): return self.name + str(self.age) user = User('xiao',5) print(user.tag)
對於tag來說使用類屬性 user.tag 的方式獲取會比 user.tag() 更加的合理。
示例2
我們使用和上文一樣的測試類,現在我們需要在讀取user的age屬性時必須在原來的基礎上+5(預處理),但是不能修改類中保存的age值,在不使用@property的情況下我們可能會這樣寫:
class User(): def __init__(self, name, age): self.name = name self._age = age def age(self): return self.age + 5 user = User('xiao',5) print(user.age())
和示例1的問題相同,我們需要用函數調用的方式來獲取預處理后的age值,而使用@property我們就可以更方便的進行預處理操作:
class User(): def __init__(self, name, age): self.name = name self._age = age @property def age(self): return self._age + 5 user = User('xiao',5) print(user.age)
我們先修改類屬性age為_age,然后為age方法加上@property裝飾器,這樣我們在外面就可以用user.age方便的獲取預處理后的值了。
通過@property我們實現了在讀取類屬性前對數據進行預處理,那么我們能不能在數據從外部存入類屬性前對數據進行預處理呢?
@*.setter
python中的@*.setter裝飾器可以總結為兩個作用:
- 對要存入的數據進行預處理
- 設置可讀屬性(不可修改)
注意:@*.setter裝飾器必須在@property裝飾器的后面,且兩個被修飾的函數的名稱必須保持一致,* 即為函數名稱。
示例1
我們使用和上文一樣的測試類,現在我們需要在數據存入user.age前先對其+5,利用@*.setter裝飾器我們可以這樣寫:
class User(): def __init__(self, name, age): self.name = name self._age = age @property def age(self): return self._age @age.setter def age(self,n): self._age = n + 5 user = User('xiao',0) user.age = 5 print(user.age)
# 結果:10
當執行 user.age = 5 時,@age.setter裝飾器下的age函數會將數據+5后再存入類屬性_age中,實現了存入前對數據的預處理。
示例2
通過@*.setter裝飾器,我們可以方便的設置只讀屬性,即無法對屬性進行修改:
class User(): def __init__(self, name, age): self.name = name self._age = age @property def age(self): return self._age @age.setter def age(self,n): print('數據不能被修改') user = User('xiao',0) user.age = 5
在為age賦值時會立即觸發@age.setter裝飾器下的age函數中的提示語句或者異常處理語句。
綜合示例
通過@*.setter和@property的組合使用我們就可以實現密碼的密文存儲和明文輸出,具體步驟為:用戶輸入明文->轉化為密文后存入->用戶讀取時先轉化為明文再輸出。
class User(): def __init__(self, name): self.name = name self._password = '' # 密文存儲 @property def password(self): return decryption(self._password) # 解密 @password.setter def password(self,word): self._password = encryption(word) # 加密 user = User('xiao') user.password = '123' #明文輸入 print(user.password) #明文輸出
總結:為兩個同名函數打上@*.setter裝飾器和@property裝飾器后,當把函數作為變量賦值時會觸發@*.setter對應的函數,當把函數作為變量讀取時會觸發@property對應的函數,因此我們可以將其用於數據的預處理。