在Java等語言的屬性訪問和設置中,通常會在類的代碼中添加getter
和setter
方法,以實現屬性的設置與獲取。
class OldResistor(object):
def __init__(self,ohms):
self._ohms = ohms
def get_ohms(self):
return self._ohms
def set_ohms(self,ohms):
self._ohms = ohms
if __name__ == '__main__':
r = OldResistor(100)
print('Before:%s'%r.get_ohms())
r.set_ohms(200)
print("After:%s"%r.get_ohms())
這種getter
和setter
形式對於Python來說較爲繁瑣,因爲每次獲取和設置屬性值都要通過函數來實現。
對於Python來說,基本上不需要手工設置setter
和getter
方法,可以將屬性的訪問權限設置爲public
。
class Resistor(object):
def __init__(self,ohms):
self.ohms = ohms
self.voltage = 0
self.current = 0
r1 = Resistor(50e3)
r1.ohms = 10e3
這樣簡單的public
屬性實現Resistor
類後,原地自增操作實現變得簡單爲:r1.ohms += 5e3
@property
或者使用@property
修飾器結合setter
方法來做。
下面這個類繼承自Resistor
,同時增加了修改current
屬性,此時我們就可以直接訪問並修改:
class Resistor(object):
def __init__(self,ohms):
self.ohms = ohms
self.voltage = 0
self.current = 0
class VoltageResistance(Resistor):
def __init__(self,ohms):
super().__init__(ohms)
self._voltage = 0
@property
def voltage(self):
return self._voltage
@voltage.setter
def voltage(self,voltage):
self._voltage = voltage
self.current = self._voltage / self.ohms
if __name__ == '__main__':
r1 = VoltageResistance(100)
print(r1.voltage)
r1.voltage = 10
print(r1.voltage)
與此同時,爲屬性設置setter
方法時,可以在方法裏面做類型驗證及數值驗證。
class BoundedResistance(Resistor):
def __init__(self,ohms) -> None:
super().__init__(ohms)
@property
def ohms(self):
return self._ohms
@ohms.setter
def ohms(self,ohms):
if ohms<=0:###數值驗證
raise ValueError('%f ohms must be > 0'%ohms)
self._ohms = ohms
如果此時傳入無效的值,那麼程序便會報錯。
再者,我們可以使用@property
來防止父類的屬性遭到修改。
class FixedResistance(Resistor):
#...
@property
def ohms(self):
return self._ohms
@ohms.setter
def ohms(self,ohms):
if hasattr(self,'_ohms'): ##驗證
raise AttributeError("Can't set attribute")
self._ohms = ohms
構建好對象後,如果試圖修改ohms
屬性,那麼就會引發異常。
需要注意的是:如果只是單純地設置@property
,沒有設置setter
那麼該屬性只讀
,兩個都設置了,才能讀寫
。
總結:其實本質上要想對類的屬性進行訪問或設置,完全可以將屬性設置爲
public
(但是沒法實現相應的驗證邏輯),或者編寫getter
r和setter
方法,但是getter
和setter
方法每次調用時,都要先調用函數再調用屬性,比較麻煩,簡便的方法就是使用@property
修改屬性函數,這樣既可以通過直接訪問屬性的方式進行修改,同時也可以編寫驗證邏輯。