@property与@{Attribute}.setter的例子
先看代码,你能读懂吗?
class Resistor:
def __init__(self, ohms):
self.ohms = ohms
class FixedResistance(Resistor):
def __init__(self, ohms):
super().__init__(ohms)
@property
def ohms(self):
return self._ohms + 1000
@ohms.setter
def ohms(self, ohms):
if hasattr(self, ‘_ohms‘):
raise AttributeError("Ohms is immutable")
self._ohms = ohms + 1
if __name__ == ‘__main__‘:
r4 = FixedResistance(1e3)
print(r4.ohms)
结果:
解析:
r4 = FixedResistance(1e3)实例化时,由于其继承了父类Resistor初始化,所以会触发属性赋值行为(self.ohms = ohms),此时就会触发FixedResistance中定义的@ohms.setter-->
def ohms(self, ohms)方法,那么self._ohms被赋值为1001,如果继续触发访问属性ohms的行为,则触发@property-->def ohms(self)方法,将则self.ohms的返回结果为1001 + 1000 = 2001.
当然如果此时,使用实例化对象继续修改_ohms的属性值,那么就会抛异常,报错!
看到了吗?此行代码可以实现“限制保护属性不被修改”
总结要点:
1、如果访问属性时确实有必要做特殊处理,那就通过@property来定义获取属性与设置属性的方法;
2、实现@property方法时,应该遵循最小惊讶原则,不要引发奇怪的副作用,此方法必须执行得很快。复杂或缓慢的任务,尤其是涉及到I/O或者会引发副作用的任务,还是用普通的方法来实现比较好。
3、@property最大的缺点是,通过它而编写的属性获取与属性设置方法只能由子类共享。与此无关的类不能共用这份逻辑。但是没关系,Python还支持描述符(descriptor),我们可以利用这种机制把早前编写的属性获取与属性设置逻辑复用到其他许多地方;
Effective Python Ver2.0_StudyNotes_纯属性与修饰器取代旧式的setter与getter方法