在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
修改属性函数,这样既可以通过直接访问属性的方式进行修改,同时也可以编写验证逻辑。