Python中@property和@setter的用法


問題引出

  在業務處理時經常需要在數據的讀取和存入前對數據進行預處理,通過@property和@*.setter兩個裝飾器就可以方便的實現。

 

@property

  python中的@property裝飾器可以總結為兩個作用:

  1. 讓函數可以像普通變量一樣使用
  2. 對要讀取的數據進行預處理

 

示例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裝飾器可以總結為兩個作用:

  1. 對要存入的數據進行預處理
  2. 設置可讀屬性(不可修改)

  注意:@*.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對應的函數,因此我們可以將其用於數據的預處理。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM