前言
今天來說一下@property裝飾器,這是個python內置的裝飾器,主要是作用是把類中的一個方法變為類中的一個屬性,並且使定義屬性和修改現有屬性變的更容易
我們可以看一下@property源碼中給的實例和解釋
1 Decorators make defining new properties or modifying existing ones easy: 2 3 4 class C(object): 5 @property 6 def x(self): 7 "I am the 'x' property." 8 return self._x 9 10 @x.setter 11 def x(self, value): 12 self._x = value 13 14 @x.deleter 15 def x(self): 16 del self._x
沒錯,龜叔給的解釋就是這個裝飾器會把定義新屬性和對現有的屬性的修改變的更簡單,那么傳統的方法在綁定屬性和訪問屬性時是什么樣的呢?
實例
1 """ 2 ------------------------------------ 3 @Time : 2019/7/4 20:57 4 @Auth : linux超 5 @File : python_property.py 6 @IDE : PyCharm 7 @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 @QQ : 28174043@qq.com 9 @GROUP: 878565760 10 ------------------------------------ 11 """ 12 13 14 class UserInfo(object): 15 16 def get_name(self): 17 """通過類的方法訪問類中的屬性""" 18 return self.__name 19 20 def set_name(self, name): 21 """通過外部傳參的方式綁定屬性""" 22 self.__name = name 23 24 25 if __name__ == '__main__': 26 user = UserInfo() 27 # 綁定name屬性 28 user.set_name(["超哥", "linux超"]) 29 print("我的名字是:", user.get_name())
執行結果
我的名字是: [’超哥’, ‘linux超’]
Process finished with exit code 0
這種方式在綁定屬性,獲取屬性時顯的很是繁瑣,而且無法保證數據的准確性,從執行結果看來,名字應該是個字符串才對,然而輸出結果卻是個列表,這並不符合實際規則
而且也沒有通過直接訪問屬性,修改屬性的方式那么直觀
我們對代碼稍作改動,並使用@property裝飾器來實現
1 """ 2 ------------------------------------ 3 @Time : 2019/7/4 22:02 4 @Auth : linux超 5 @File : python_class.py 6 @IDE : PyCharm 7 @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 @QQ : 28174043@qq.com 9 @GROUP: 878565760 10 ------------------------------------ 11 """ 12 13 14 class UserInfo(object): 15 @property 16 def name(self): 17 return self.__name 18 19 @name.setter 20 def name(self, name): 21 if isinstance(name, str): 22 self.__name = name 23 else: 24 raise TypeError("The name must be str") 25 26 27 if __name__ == '__main__': 28 user = UserInfo() 29 # 綁定屬性 30 user.name = "linux超" 31 print("我的名字是", user.name) 32 user.name = ["linux超", "超哥"] 33 print("我的名字是", user.name)
執行結果
我的名字是 linux超 Traceback (most recent call last): File "D:/LingMengPython16/LingMengPython16/cnblogs/python_class.py", line 32, in <module> user.name = ["linux超", "超哥"] File "D:/LingMengPython16/LingMengPython16/cnblogs/python_class.py", line 24, in name raise TypeError("The name must be str") TypeError: The name must be str Process finished with exit code 1
經過優化后的代碼我們可以看到當綁定的屬性並非是一個字符串類型時,就會報錯,而且我們可以直接通過類似訪問屬性的方式來綁定屬性,訪問屬性,這樣就更加直觀了
這里有個點需要注意,@name.setter中name這個名字極其被他修飾的方法名字與@property修改的方法名必須保持一致,否則會報錯
其中@name.setter裝飾器是因為使用了@property后他本身創建的裝飾器
其實呢,我覺得@perproty裝飾器並不僅僅只用來綁定屬性和訪問屬性,還可以用來在類的外部訪問私有成員屬性
先來看個類的外部直接訪問私有成員的實例
1 """ 2 ------------------------------------ 3 @Time : 2019/7/4 20:57 4 @Auth : linux超 5 @File : python_property.py 6 @IDE : PyCharm 7 @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 @QQ : 28174043@qq.com 9 @GROUP: 878565760 10 ------------------------------------ 11 """ 12 13 14 class UserInfo(object): 15 16 def __init__(self, name, age): 17 self.__name = name 18 self.__age = age 19 20 if __name__ == '__main__': 21 user = UserInfo('linux超', 18) 22 print(user.__name)
執行結果
Traceback (most recent call last): File "D:/LingMengPython16/LingMengPython16/cnblogs/python_property.py", line 22, in <module> print(user.__name) AttributeError: 'UserInfo' object has no attribute '__name' Process finished with exit code 1
沒錯,程序是沒辦法運行成功的,因為python不允許你在類的外部訪問類中的私有成員,這么做其實是為了保護數據的安全性
那么這時候我們也可以使用@property裝飾器來訪問類的屬性
1 """ 2 ------------------------------------ 3 @Time : 2019/7/4 20:57 4 @Auth : linux超 5 @File : python_property.py 6 @IDE : PyCharm 7 @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 @QQ : 28174043@qq.com 9 @GROUP: 878565760 10 ------------------------------------ 11 """ 12 13 14 class UserInfo(object): 15 16 def __init__(self, name): 17 self.__name = name 18 19 @property 20 def name(self): 21 """通過類的方法訪問類中的私有屬性""" 22 return self.__name 23 24 if __name__ == '__main__': 25 user = UserInfo('linux超') 26 print("獲取name屬性:", user.name)
執行結果
獲取name屬性: linux超
Process finished with exit code 0
這樣就能訪問類的私有成員屬性了
那么其實我個人認為,相對於綁定屬性來說這種方式用的比較多,當你不想子類繼承父類時,防止子類修改父類的屬性,那么你完全就可以使用這種方法來避免屬性被修改,而且在子類和類的外部還可以正常訪問這個私有屬性
總結
@property裝飾器主要用來改變一個方法為一個屬性,且需要注意幾點
1. 被此裝飾器裝飾的方法不能傳遞任何除self外的其他參數
2.當同時使用@property和@x.setter時 需要保證x以及被@x.setter修改的方法名字與@property修改的方法名字必須保持一致