Как сделать так, чтобы декоратор свойств вызывался при модификации атрибута на месте? - PullRequest
0 голосов
/ 08 мая 2019

Я хотел бы знать, как заставить @property декоратор вызывать конструктор при изменении объекта, а не назначать его.

class Celsius:
    def __init__(self, temperature = [0]):
        self._temperature = temperature
    @property
    def temperature(self):
        print("Getting value")
        return self._temperature
    @temperature.setter
    def temperature(self, value):
        print('setting temperature')
        self._temperature = value
a=Celsius()
a.temperature
Getting value
Out[10]: [0]
a.temperature = 7
setting temperature
a.temperature = [7,8]
setting temperature
a.temperature[0] = 0
Getting value
a.temperature
Getting value
Out[14]: [0, 8]

Как видите, при назначении температуры свойство вызывается между тем, еслисписок изменен, он не вызывает конструктор, но вызывает «displayer»

Я знаю, что это, вероятно, не сделано с @property, но это самая близкая идея, которую я нашел.

На самом делекак это меняет значение температуры и _температура на месте?

Ответы [ 2 ]

0 голосов
/ 08 мая 2019

Последовательность:

>>> a=Celsius()
>>> a.temperature = [7,8]
setting temperature
>>> a.temperature[0] = 0
getting value

Особенно интересно, потому что вы дали доступ к списку _temperature, а злой пользователь может сломать вам экземпляр Celsius. Хотелось бы что-то вроде этого:

>>> a=Celsius()
>>> a.temperature = [7,8]
setting temperature (I CHECK THAT THOSE VALUES ARE CONSISTENT)
>>> a.temperature[0] = 0
setting ONE temperature (I CHECK THAT THIS VALUE IS CONSISTENT)

По сути, вы потеряли контроль над своим объектом, потому что вы не можете проверить, что может сделать злой пользователь. Это кажется опасным дизайном. Вот предложение: никогда не делитесь изменяемым объектом с внешним миром, всегда предоставляйте неизменный объект или копию. (Это обеспечивает соблюдение Закона Деметры ). Заменить:

@property
def temperature(self):
    print("getting value")
    return self._temperature

Автор:

@property
def temperature(self):
    print("getting value")
    return list(self._temperature)

И попробуйте свой тестовый пример:

>>> a=Celsius()
>>> a.temperature = [7,8]
setting temperature (I CHECK THAT THOSE VALUES ARE CONSISTENT)
>>> a.temperature[0] = 0
getting value
>>> a.temperature
getting value
[7, 8] # NO MODIFICATION HERE

Теперь ваш объект Celsius защищен от диких модификаций: если вы хотите изменить список _temperature, вы должны предоставить полный список, который должен быть проверен установщиком.

Если вы хотите изменить одно значение, это все еще возможно, но есть вызов к установщику (и возможная проверка):

>>> a=Celsius()
>>> a.temperature = [7,8]
setting temperature (I CHECK THAT THOSE VALUES ARE CONSISTENT)
>>> new_temp = [0] + a.temperature[1:]
getting value
>>> a.temperature = new_temp
setting temperature (I CHECK THAT THOSE VALUES ARE CONSISTENT)
>>> a.temperature
getting value
[0, 8]

Если вы абсолютно хотите, чтобы пользователь устанавливал элемент по индексу, вы должны написать функцию вручную:

class Celsius:
    ...

    def set_temperature_item(self, i, v):
        print ("setting ONE temperature (I CHECK THAT THIS VALUE IS CONSISTENT)")
        self._temperature[i] = v

>>> a=Celsius()
>>> a.temperature = [7,8]
setting temperature (I CHECK THAT THOSE VALUES ARE CONSISTENT)
>>> a.set_temperature_item(0, 0)
setting ONE temperature (I CHECK THAT THIS VALUE IS CONSISTENT)
>>> a.temperature
getting value
[0, 8]

Недвижимость

Я думаю, что вы не можете сделать это с property, потому что когда вы пишете:

a.temperature[0] = 0

Это эквивалентно:

a.__getattribute__("temperature").__setitem__(0, 0)

И вы не можете решить по вызову __getattribute__, что будет дальше: просто получите значение или используйте его для установки элемента.

0 голосов
/ 08 мая 2019

Причина, по которой вы видите вывод «Получение значения» при установке значения, заключается в том, что вы изменяете переменную _teuration.

Чтобы изменить переменную, она должна быть извлечена первой.Когда вы перезаписываете переменную, ее не нужно сначала извлекать, и ее можно просто установить.

Причина, по которой вы не видите вывод «установка температуры», заключается в том, что вы на самом деле модифицируете базовый объект _tempera,список, так что ваш установщик свойства не используется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...