1. 程式人生 > 實用技巧 >python內建裝飾器@property

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

沒錯,龜叔給的解釋就是這個裝飾器會把定義新屬性和對現有的屬性的修改變的更簡單,那麼傳統的方法在繫結屬性和訪問屬性時是什麼樣的呢?

例項

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裝飾器來實現

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裝飾器並不僅僅只用來繫結屬性和訪問屬性,還可以用來在類的外部訪問私有成員屬性

先來看個類的外部直接訪問私有成員的例項

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裝飾器來訪問類的屬性

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修改的方法名字必須保持一致