python @property 用法笔记
https://www.programiz.com/python-programming/property
举个例子:
设计一个类:
class Celsius:
def __init__(self, temperature = 0):
self.tmperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
用法如下:
man = Celsius()
man.temperature = 37
man.temperature # output: 37
man.to_fahrenheit # output: 98.60000000000001
当我们为对象属性进行赋值或读取时(如上文的 temperature
),Python 会在它的 __dict__
字典中进行查找:
man.__dict__
# output: {'temperature': 37}
因此 man.temperature
实际上是 man.__dict__['temperature']
。
现在我要加功能,保证摄氏度不低于 -273 (实际不能低于 -273.15)。
使用 Getters 和 Setters 来对属性进行读取或赋值:
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):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
self._temperature = value
此时赋值为小于 -273 时则会报错。
然而,对于其他使用这段程序的部分来说,原来他们需要访问的地方都要从 obj.temperature
改成 obj.get_temperature
,而赋值的地方 obj.temperature = val
要改成 obj.set_temperature(val)
,这很麻烦。
使用 @property
:
class Celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
def get_temperature(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)
最后一行定义了一个 property object temperature
,也就是说 property 将一些函数 get_temperature,set_temperature
加到了成员属性访问(temperature
)上了。
任意使用到 temperature
的地方会自动调用 get_temperature
而不是 __dict__
,任意给 temperature
赋值的地方都会自动调用 set_temperature
。
则此时:
会发现在创建一个对象时,会调用 set_temperature
,原因是 __init__
方法里有一句 self.temperature = temperature
,这句话自动调用了 set_temperature
。
通过使用 property
,我们可以对下游代码不进行修改而添加上相应的功能。注意此时 temperature
时一个 property object,它为私有变量提供一个接口,真正的值存放在 _temperature
中。
在 Python 中,property()
是一个 built-in function ,它创建并返回一个 property object:
property(fget=None, fset=None, fdef=None, doc=None)
其中 fget,fset,fdel,doc
分别是取值函数、赋值函数、删除属性操作、注释(一个 string)
一个 property object 有三个 methods :getter(),setter(),deleter()
,所以
temperature = property(get_temperature,set_temperature)
相当于:
temperature = property()
temperature = temperature.getter(get_temperature)
temperature = temperature.setter(set_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
假如说只定义 getter
而不定义 setter
的话(没有 @temperature.setter
),此时该属性为只读属性