python內置裝飾器@property

前言

今天來說一下@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   : [email protected]
 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   : [email protected]
 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   : [email protected]
 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   : [email protected]
 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修改的方法名字必須保持一致

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