python @property详解

上一篇 / 下一篇  2017-04-25 10:45:26 / 个人分类:Python

@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())
输出结果:
37
98.6
当我们获取对象属性,或者对对象属性进行赋值时,像这里的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



TAG: Python

 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

Open Toolbar