当属性用作装饰器时,设置器不会引发异常

时间:2019-06-27 14:15:01

标签: python exception properties decorator setter

我正在学习Python, @property 发生了一件奇怪的事情,我不明白...

我找到了一个有关财产如何运作的示例here,发现这一点很清楚。 以下代码可以正常工作:

class Celsius:

    def __init__(self, temperature=0):
        self.temperature = temperature

    def to_farenheit(self):
        return (self.temperature * 1.8) + 32

    def get_temperature(self):
        print("Getting value")  # just to see on screen when we call it
        return self._temperature

    def set_temperature(self, value):
        print("Setting value")  # just to see on screen when we call it
        if value < -273:
            raise ValueError("Temperature cannot be less than -273 °C !")
        self._temperature = value

    temperature = property(get_temperature, set_temperature)

当我们尝试将温度设置为绝对零以下时,我们看到调用了setter并引发了ValueError:

T = Celsius(-400)
>>> Setting value
>>> Traceback (most recent call last):
>>> ...
>>> ValueError: Temperature cannot be less than -273 °C !

但是,当我们将属性定义为装饰器(即 @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):
        print("Setting value")
        if value < -273:
            raise ValueError("Temperature below -273 is not possible")
        print("Setting value")
        self._temperature = value

我们做同样的事情,不调用setter,也不会引发异常:

T = Celsius(-400)
print(T.temperature)
>>> Getting value
>>> -400

即使我们更改T的值,看起来也从未调用过 @ temperature.setter

T = Celsius(20)
print(T.temperature)
>>> Getting value
>>> -400

我不明白...有人可以向我解释吗?

1 个答案:

答案 0 :(得分:1)

在类初始化器中,您将输入temperature设置为实例属性_temperature,但具有属性temperature的属性获取器和设置器。

在当前形式下,如果要设置属性temperature,则会得到所需的异常:

In [505]: c = Celsius(-400)                                                                                                                                                                                 

In [506]: c.temperature                                                                                                                                                                                     
Getting value
Out[506]: -400

In [507]: c.temperature = -500                                                                                                                                                                              
Setting value
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-507-2b9ed72eeb52> in <module>
----> 1 c.temperature = -500

<ipython-input-504-e44aad21660f> in temperature(self, value)
     15         print("Setting value")
     16         if value < -273:
---> 17             raise ValueError("Temperature below -273 is not possible")
     18         print("Setting value")
     19         self._temperature = value

ValueError: Temperature below -273 is not possible

你去了。

现在,如果将__init__更改为将输入temperature设置为temperature属性,则在初始化类时会得到异常:

In [508]: 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): 
     ...:         print("Setting value") 
     ...:         if value < -273: 
     ...:             raise ValueError("Temperature below -273 is not possible") 
     ...:         print("Setting value") 
     ...:         self.temperature = value 
     ...:                                                                                                                                                                                                   

In [509]: c = Celsius(-400)                                                                                                                                                                                 
Setting value
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-509-1fc014754084> in <module>
----> 1 c = Celsius(-400)

<ipython-input-508-af8466917803> in __init__(self, temperature)
      1 class Celsius:
      2     def __init__(self, temperature = 0):
----> 3         self.temperature = temperature
      4 
      5     def to_fahrenheit(self):

<ipython-input-508-af8466917803> in temperature(self, value)
     15         print("Setting value")
     16         if value < -273:
---> 17             raise ValueError("Temperature below -273 is not possible")
     18         print("Setting value")
     19         self.temperature = value

ValueError: Temperature below -273 is not possible

为什么您的第一个代码有效?

在第一个代码中,您已将属性temperature设置为temperature中的输入__init__

由于使用了property可调用(它是一个描述符),python看到您有一个描述符temperature,同时它也是一个数据描述符,同时还有一个setter。因此,它尝试调用setter方法来设置值。