背景
调用一个实例或类的属性时,会返回其存储的值。在不使用property的情况下,通常要使用方法来实现对属性的修改或约束。这样带来的问题是,当类添加或修改了属性的方法,调用方就要修改其代码,来满足变更。
class Celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
此时的调用方式是obj.temperature
.但调用方发现,稳定不能低于-273.15.要实现这个约束,将代码修改为如下:
class Celsius:
def __init__(self, temperature = 0):
self.set_temperature(temperature)
def to_fahrenheit(self):
return (self.get_temperature() * 1.8) + 32
# new update
def get_temperature(self):
return self._temperature
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
self._temperature = value
此时所有调用这个类的代码都要从obj.temperature
的形式改成obj.get_temperature()
.且所有的类似obj.temperature=val
的语句都要重构成obj.set_temperature(val)
的样式。如果量大的话,这对调用方来说可能是个灾难。
因此这里引出property的使用场景,就是像访问属性一样实现对方法的调用。还有一种常用场景是,对属性的保护。
使用场景
1 装饰方法,使方法像属性一样访问
使用property装饰器修改背景中的代码,如下:
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
>>> c.temperature
Getting value
0
>>> c.temperature = 37
Setting value
>>> c.to_fahrenheit()
Getting value
98.60000000000001
2 对属性做限定
使用property可以对属性做只读限制,防止被修改。
class Student(object):
@property # 把一个getter方法变成属性,只需要加上@property即可
def birth(self):
return self._birth
@birth.setter # @birth.setter负责把一个setter方法编程一个属性赋值
def birth(self, value):
self._birth = value
@property
def age(self):
return 2015 - self._birth
只定义getter方法,不定义setter方法就是一个只读属性,如上面的age
。因为age
可以根据birth
和当前的时间计算出来。
Reference
1 https://www.programiz.com/python-programming/property
2 https://www.liaoxuefeng.com/wiki/1016959663602400/1017502538658208