@property装饰器
1.对对象属性进行管理,包括赋值,对赋值的范围是否正确进行检查并提示相关信息
2.外部可以方便快捷的调用对象属性值,对对象属性进行赋值
一个简单例子我们创建一个类,定义一个temperature的变量,以及一个函数to_fahrenheit,用于将摄氏单位转化为华氏单位
class Celsius():
def __init__(self,temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
if __name__ == '__main__':
c = Celsius()
c.temperature = 37
print(c.temperature)
print(c.to_fahrenheit())
输出结果:
当我们获取对象属性,或者对对象属性进行赋值时,像这里的temperature属性,获取属性值,其实是搜索了对象的__dict__字典,
>>> c.__dict__
{'temperature': 37}
内部处理的是c.__dict__['temperature'].
假设此class由developerA开发,并且此class已经在项目中广泛使用,通过obj.temperature = value1的方式赋值,obj.temperature的方式取值。
有一天,客户告知我们temperature的值需要限制为不能小于-273,小于这个值时系统提示错误。我们该如何修改?
使用Getter和Setter
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,value):
if value < -273:
raise ValueError('temperature below -273 is not possible ')
else:
self._temperature = value
>>> c = Celsius(37)
>>> c.get_temperature()
37
>>> c = Celsius(-370)
Traceback (most recent call last):
File "<pyshell#32>", line 1, in <module>
c = Celsius(-370)
File "C:/Python27/Scripts/simple_test.py", line 4, in __init__
self.set_temperature(temperature)
File "C:/Python27/Scripts/simple_test.py", line 14, in set_temperature
raise ValueError('temperature below -273 is not possible ')
ValueError: temperature below -273 is not possible
代码解决了对temperature进行赋值限制的问题
但是引发了新的问题:1.通过obj.temperature = value1的方式赋值需改为obj.set_temperature,obj.temperature的方式取值需改为obj.get_temperature.显然我们不能让使用到这个对象的代码改动。最好的办法是修改这个class文件,让其可以用最开始的方式对属性进行赋值和取值。
使用@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)
代码最后部分,使用
python的property特性,对temperature赋值。
>>> c = Celsius(37)
>>> c.temperature
37
>>> c.temperature = 45
>>> c.temperature
45
所以,当对属性赋值时,会自动调用get_temperature。
注意:真正temperature的值时存储在私有变量_temperature中的,temperature是一个property对象,提供_了t一个emperature接口。
深入了解property对象
propery是一个内置函数,返回值是一个property对象,参数如下:
property(fget=None, fset=None, fdel=None, doc= None)
fget指一个get方法,fset指一个set方法,fdel可以删除一个属性,doc是一些说明文字,可以看出这些参数都是可选的(如果不指定,使用默认值None)。
对上述代码,一个Pythonic的写法是使用@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 = Celsius(37)
>>> c.temperature
Getting value
37
至此,如果我们是class Celsius的使用者,就可以很简单的通过obj.temperature = value1的方式赋值,obj.temperature的方式取值了,并且如果temperature的值超出限制范围也可以得到相应的提示
最后,我们以一个简单的例子来总结property的用法
class MyTest(object):
def __init__(self,x):
self.x = x
@property
def x(self):
return self.x
@x.setter
def x(self,x):
if x < 0:
raise ValueError('cannot be smaller than 0')
if x > 100:
raise ValueError('cannot be greater than 100')
a = MyTest(2000)
输出:
raise ValueError('cannot be greater than 100')
ValueError: cannot be greater than 100