第29条 用纯属性@property取代get和set方法

在Java等语言的属性访问和设置中,通常会在类的代码中添加gettersetter方法,以实现属性的设置与获取。

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())

这种gettersetter形式对于Python来说较为繁琐,因为每次获取和设置属性值都要通过函数来实现。

对于Python来说,基本上不需要手工设置settergetter方法,可以将属性的访问权限设置为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(但是没法实现相应的验证逻辑),或者编写getterr和setter方法,但是gettersetter方法每次调用时,都要先调用函数再调用属性,比较麻烦,简便的方法就是使用@property修改属性函数,这样既可以通过直接访问属性的方式进行修改,同时也可以编写验证逻辑。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章