Когда свойство используется в качестве декоратора, установщик не вызывает исключение - PullRequest
1 голос
/ 27 июня 2019

Я изучаю Python, и с @ property происходит одна странная вещь, которую я не понимаю ...

Я нашел пример здесь о том, как работает свойство, и нашел его довольно понятным. Следующий код работает нормально:

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)

Когда мы пытаемся установить температуру ниже абсолютного нуля, мы видим, что вызывается установщик и возникает ошибка 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

И мы делаем то же самое, сеттер не вызывается и исключение не вызывается:

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

Похоже, что @tempera.setter никогда не вызывается, даже когда мы меняем значение T:

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

Я не понимаю ... кто-то может мне это объяснить?

1 Ответ

1 голос
/ 27 июня 2019

В вашем инициализаторе класса вы устанавливаете ввод temperature в качестве атрибута экземпляра _temperature, но у вас есть свойство getter и setter для атрибута 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

Вот и все.

Теперь, если вы измените yor __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 callable (который является дескриптором), python видит, что у вас есть дескриптор temperature иэто дескриптор данных, так как у вас также есть сеттер.Поэтому он пытается вызвать метод установки для установки значения.

...