Python中的 property特性

Python中的 property特性

你將瞭解Python中的 @property特性, 以pythonic的方式使用getter和setter。

目錄表

  • 從一個例子開始

  • 使用 Getter 和 Setter

  • @property的力量

  • 深入理解Property

Python有一個很棒的概念,叫做property,它使面向對象的程序員的生活更加簡單。

在定義和研究@property是什麼之前,讓我們先直觀感受下為什麼首先應該使用它。

從一個例子開始

我們假設你決定創建一個可以以攝氏度存儲溫度的類[1],它還將實現一個將溫度轉換為華氏度的方法。一種方法是像下面這樣做。

Python中的 property特性

我們可以使用這個類創建對象,並按照我們的意願操作其屬性temperature。你可以在Python shell上試試這些操作。

Python中的 property特性

在轉換成華氏溫度時,由於浮點運算錯誤(請在Python解釋器中嘗試1.1 + 2.2),小數點多了一位。

當我們賦值或檢索任何對象屬性像temperature時,如上面所示,Python都會在該對象的__dict__字典中搜索它。

Python中的 property特性

因此, man.temperature在內部會變成 man.__dict__['temperature']。

現在,讓我們進一步假設我們的類在客戶中很受歡迎,他們開始在自己的程序中使用它。他們對這個對象做了各種各樣的賦值操作。

有一天,一個值得信賴的客戶來找我們,建議溫度不能低於-273攝氏度(熱力學專業的學生可能會說實際上是-273.15攝氏度),也被稱為絕對零度。他還要求我們實現這個值約束。作為一家追求客戶滿意的公司,我們很高興地採納了這個建議,併發布了1.01版本(對現有的類進行升級)。

使用Getter和Setter

上述對值進行約束的一個明顯解決方案是隱藏屬性temperature(使其私有)並定義新的 getter 和 setter 接口來操作它。可以按照下面這樣做。

Python中的 property特性

從上面可以看出,我們定義了get_temperature和set_temperature兩個新方法,並且用 _temperature 替換了temperature。在Python中,開頭的下劃線 (_) 用於表示私有變量。

Python中的 property特性

這次更新成功地實現了新的限制。我們沒法再將溫度設置在-273度以下。

請注意,Python中不存在私有變量,但還是有一些簡單的準則可以遵循。Python語言本身並不會做限制。

Python中的 property特性

但這並不是什麼大問題。上述更新的一個大問題是,所有在其程序中實現我們前面的類的客戶都必須修改他們的代碼,將obj.temperature修改為 obj.get_temperature,並且將像 obj.temperature = val 的所有賦值語句修改為obj.set_temperature(val)。

這種重構可能會給客戶帶來數十多萬行代碼的麻煩。

總之,我們的新更新不向後兼容。這時property就派上用場了。

@property的力量

處理上述問題的Pythonic的方法是使用property。以下是我們如何實現它。

Python中的 property特性

然後,在shell中運行以下代碼並注意觀察。

Python中的 property特性

我們在 get_temperature 和 set_temperature 中添加了一個 print 函數,來清楚地觀察它們是否正在執行。

代碼的最後一行創建了一個property對象 temperature。簡單地說,property將一些代碼( get_temperature 和 set_temperature )附加到成員屬性訪問中( temperature )。

任何檢索 temperature 值的代碼都將自動調用 get_temperature,而不是使用字典(__dict__)進行查找。類似地,任何對temperature 賦值的代碼都會自動調用 set_temperature。這是Python中一個很酷的特性。

我們可以看到上面的 set_temperature 即使在創建對象時也被調用。

你能猜到這是為什麼嗎?

原因是在創建對象時, __init__ 方法被調用。這個方法有 self.temperature = temperature 這行代碼,所以賦值時會自動調用set_temperature。

Python中的 property特性

類似地,任何訪問,比如 c.temperature,都會自動調用 get_temperature。這就是property的作用。這裡有更多的幾個例子。

Python中的 property特性

通過使用 property,可以看到,我們修改了類並實現了對值的約束,而不需要對客戶代碼進行任何更改。因此,我們的實現是向後兼容的,皆大歡喜。

最後請注意,實際的溫度值存儲在私有變量 _temperature中。屬性 temperature是一個property對象,它為這個私有變量提供接口。

深入理解 Property

在Python中,property是一個內置函數,用於創建和返回一個property對象。這個函數的簽名是:

Python中的 property特性

其中,fget 是獲取屬性值的函數,fset 是設置屬性值的函數,fdel 是刪除屬性的函數,doc 是字符串(像註釋一樣)。從上述實現中可以看出,這些函數參數是可選的。因此,可以按照以下方式創建property對象。

Python中的 property特性

property對象有三個方法,getter、setter 和 deleter,用於後續指定 fget、fset 和 fdel。這意味著本行代碼

Python中的 property特性

可以分解為

Python中的 property特性

這兩段代碼是等價的。

熟悉Python中的裝飾器[2]的程序員可能會意識到,上面的構造可以實現為裝飾器。

我們可以繼續,不去定義 get_temperature 和 set_temperature名稱,因為它們是不必要的,並且會汙染類命名空間。為此,我們在定義 getter 和 setter 函數時重用了名稱 temperature。這就是它實現的方式。

Python中的 property特性

上述實現是既簡單又推薦使用的創建property的方法。當你在Python中尋找property時,你很可能會遇到這些類型的構造。

好了,今天就到這裡。

相關鏈接:

[1]——https://www.programiz.com/python-programming/class

[2]——https://www.programiz.com/python-programming/decorator

英文原文:https://www.programiz.com/python-programming/property
譯者:野生大熊貓


分享到:


相關文章: