學習 python 的時候,經常遇見 @property 關鍵字,有時候讓我有點疑惑,所以寫下這篇部落格來記錄它。
在繫結屬性時,如果我們直接把屬性暴露出去,雖然寫起來很簡單,但是,沒辦法檢查引數,導致可以隨便更改屬性
舉個例子:
class celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
>>>c = celsius()
>>>c.temperature = 37
37>>>c.to_fahreheit()
98.60000000000001
這顯然不好。為了限制 temperature 的範圍,可以通過乙個 set_temperature() 方法來設定溫度,再通過乙個 get_temperature() 來獲取溫度,這樣,在 set_temperature() 方法裡,就可以檢查引數:
class celsius:
def __init__(self, temperature = 0):
self.set_temperature(temperature)
def to_fahrenheit(self):
return (self.get_temperature() * 1.8) + 32
def get_temperature(self):
return self._temperature
def set_temperature(self, value):
if value < -273:
raise valueerror("temperature below -273 is not possible")
self._temperature = value
我們在上面設定了 get_termperature() 跟 set_temperature(),並且temperature 被 _temperature 所取代(在python 中,以 _ 開頭的變數都表示為私有變數)
>>> c = celsius(-277)
traceback (most recent call last):
...valueerror: temperature below -273 is not possible
>>> c = celsius(37)
>>> c.get_temperature()
37>>> c.set_temperature(10)
>>> c.set_temperature(-300)
traceback (most recent call last):
...valueerror: temperature below -273 is not possible
更新之後,我們不允許 _termperature 低於 -273。
但是這也帶來了大問題:上面的呼叫方法略顯複雜,沒有直接用屬性這麼直接簡單,這會造成很多多餘的**。
所以這裡就是 @property 可以大展身手的時候了
看下面的**:
class celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
def c(self):
print("getting value")
return self._temperature
def set_temperature(self, value):
if value < -273:
raise valueerror("temperature below -273 is not possible")
print("setting value")
self._temperature = value
temperature = property(get_temperature,set_temperature)
對上面**的解釋:
(1)我們在 get_temperature() 和 set_temperature() 中新增了乙個 print() ,以清楚地看到它們什麼時候被執行。
(2)**的最後一行創造了乙個屬性物件:溫度。 簡單地說,屬性將一些**(get_temperature和set_temperature)附加到成員屬性訪問(temperature)。
(3)任何返回 temperature 的**將自動呼叫 get_temperature() 。 類似地,將 value 分配給 terperature 的任何**將自動呼叫 set_temperature()。
執行下面的**
>>> c = celsius()
>>> c.temperature
getting value
0
可能一開始看到結果的時候會有點不理解?為什麼會會返回getting value(證明呼叫了 set_temperature())?
原因是當建立物件時,__init__()方法被呼叫。 該方法具有 self.temperature = temperature。這個賦值自動呼叫set_temperature。
>>> c.temperature = 37
setting value
>>> c.to_fahrenheit()
getting value
98.60000000000001
最後注意,實際溫度值儲存在私有變數_temperature中。
深入了解 property
在python中,property()是乙個內建函式,它建立並返回乙個屬性物件。
property(fget=none, fset=none, fdel=none, doc=none)
其中,fget是獲取屬性值的函式,fset是設定屬性值的函式,fdel是刪除屬性的函式,doc是乙個字串。這些函式引數是可選的。
你也可以創造乙個 property()
>>> property()
乙個 property 物件有三個方法getter(),setter()和delete()來指定fget,fset和fdel。
temperature = property(get_temperature,set_temperature)
解釋:get_temperature 跟 set_temperature 是上面類的方法
我們可以不定義 get_temperature() 和 set_temperature() ,因為它們是不必要的。然而,我們在定義 getter 和 setter 函式時,可以重複使用 temperature
class celsius:
def __init__(self, temperature = 0):
self._temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
@property
def temperature(self):
print("getting value")
return self._temperature
@temperature.setter
def temperature(self, value):
if value < -273:
raise valueerror("temperature below -273 is not possible")
print("setting value")
self._temperature = value
這種寫法是推薦使用的,並且也是比較簡單的。
總結:(1)如果乙個方法是用來獲取乙個值的話,那它就應該用 「@property」 來進行裝飾
(2)如果乙個方法是用來 setter 的話,它應該用 "@x.setter" 來進行裝飾( x 是函式的名字,如果函式被稱為「f」,我們將必須使用「@ f.setter」進行裝飾。)
學習 @property 參考了一些學習資料:
(1)(2)
python之with關鍵字
with表示式其實是try finally的簡寫形式。但是又不是全相同。格式with context as var pass 其中的context是乙個表示式,返回的是乙個物件,var用來儲存context表示式返回的物件,可以有單個或者多個返回值。但是with本身並沒有異常捕獲的功能,但是如果發生...
new關鍵字 this關鍵字 base關鍵字
使用new,所做的三件事 1.類是引用物件,引用物件是在堆中開闢空間 在堆中開闢空間 2.在開闢的堆空間中建立物件 3.呼叫物件的構建函式 4.隱藏父類成員 子類的成員可以與隱藏從父類繼承的成員,類似於重寫。public new void sayhello this關鍵字的使用 1.代表當前類的物件...
python基礎之關鍵字 三
開發人員在程式中自定義的一些符號和名稱 標示符是自己定義的,如變數名 函式名等 起乙個有意義的名字,盡量做到看一眼就知道是什麼意思 提高 可 讀性 比如 名字 就定義為 name 定義學生 用 student 小駝峰式命名法 lower camel case 第乙個單詞以小寫字母開始 第二個單詞的首...