Понимание того, как частная переменная, украшенная @property, используется в python

Ниже приведен мой фрагмент кода

class TestClass:
    def __init__(self,n1,n2):
        self.n1 = n1
        self.n2 = n2
        self._sum = None # WILL BE COMPUTED LATER ON

    @property
    def sum(self):
        if self._sum is None:
           self._sum = self.compute_sum()
        return self._sum

    def compute_sum(self):
        return(self.n1+self.n2)

test_obj = TestClass(5,6)

print(test_obj.sum)

Это просто пример программы, иллюстрирующий проблему, с которой я столкнулся. У меня есть класс с частной переменной _sum, в которой я хотел бы сохранить значение двух чисел n1 и n2.

Сумма свойств может использоваться внешним миром (так сказать) для доступа к значению суммы без возможности изменения ее значения. Причина, по которой у меня есть частная переменная _sum, заключается в том, что значение вычисляется один раз и сохраняется для последующих выборок.

Просто наличие @property будет вычислять значение каждый раз, когда кто-то пытается получить доступ к значению суммы через экземпляр, и я бы хотел избежать этого, учитывая влияние на производительность (имейте в виду, это всего лишь пример, иллюстрирующий реальную проблему, с которой я столкнулся)

Учитывая мое требование иметь возможность суммировать все внешние объекты для использования, но в то же время не вычислять его каждый раз, когда он вызывается, правильна ли моя реализация с точки зрения дизайна?

Также довольно интересно, что значение _sum вычисляется еще до вызова функции, по крайней мере, моя IDE смогла это сделать, не знаю, как это сделать.

На скриншоте ниже мы находимся в строке 9, и compute_sum () не вызывается, но значение уже вычислено. Как придешь ?

enter image description here

Как написано в настоящее время, предварительно вычисленная сумма не пересчитывается при изменении n1 или n2. Либо вычисляйте сумму по запросу каждый раз, либо создайте свойства n1 и n2, которые обновят сумму, если какое-либо значение изменится.

chepner 13.09.2018 19:23

Ваша IDE, похоже, обратилась к атрибуту, чтобы показать ссылку на переменные self.

Martijn Pieters 13.09.2018 19:23

Когда ваш отладчик получил значение для self.sum, оно было вычислено. Самоанализ вызвал побочный эффект. Самоанализ требует самоанализа.

Steven Rumbalski 13.09.2018 19:24
self._sum установлен None в инициализаторе вашего класса, поэтому, как только вы создадите testobj, testobj._sum будет None.
rocksportrocker 13.09.2018 19:25

@StevenRumbalski Могу ли я использовать отладчик таким образом, чтобы он не влиял на выполнение / выборку?

Dhiwakar Ravikumar 13.09.2018 19:25

@DhiwakarRavikumar: Я не уверен, почему PyCharm на самом деле это делает, но я не могу найти для этого никаких настроек. Предположительно это является PyCharm?

Martijn Pieters 13.09.2018 19:29

@MartijnPieters да :(

Dhiwakar Ravikumar 13.09.2018 19:31

Ваш скриншот не имеет для меня особого смысла. _sum - это None, а sum - 11. Возможно, вы раньше допустили опечатку и забыли сохранить исправленный файл? У меня не установлен PyCharm, чтобы проверить, что происходит со свойствами.

Martijn Pieters 13.09.2018 19:34

Во всяком случае, код, который вы опубликовали работает нормально. Если ваш отладчик показывает, что sum установлен на 11, а в то же время показывает, что _sum установлен на None, то это либо ошибка в отладчике, либо вы не показали нам фактический код, который мог быть запущен интерпретатором до того, как вы изменили Это.

Martijn Pieters 13.09.2018 19:35

@MartijnPieters: Кажется вероятным, что PyCharm получил доступ к _sum, нашел None, обратился к sum, нашел 11, а затем не стал возвращаться и снова проверять _sum.

user2357112 supports Monica 13.09.2018 19:37

@StevenRumbalski: однако это не складывается. Если self.sum произвел 11, значит, он был вычислен и self._sum уже назначен. Тем не менее, та же область на скриншоте ясно показывает, что _sum все еще является None.

Martijn Pieters 13.09.2018 19:37

@ user2357112: тоже возможно. Тем не менее, я бы посчитал это ошибкой в ​​PyCharm, если пользовательский интерфейс не может правильно отслеживать переменные.

Martijn Pieters 13.09.2018 19:38

@MartijnPieters: В этой точке останова, где он исследует self, сначала он захватывает self._sum, который является None, затем self.n1, который является 5, затем self.n2, который является 6, затем он захватывает self.sum, который вызывает вызов метода. После этого self._sum будет 11, но отладчик уже изучил его и пропустил изменение.

Steven Rumbalski 13.09.2018 19:42

Я обновил снимок экрана тем, что сейчас наблюдаю, тот же код, но теперь вычислено _sum.

Dhiwakar Ravikumar 13.09.2018 19:44

@StevenRumbalski: имеет смысл, жаль, что PyCharm нельзя сказать, чтобы он держался подальше от дескрипторов свойств.

Martijn Pieters 13.09.2018 19:46

На вашем новом снимке экрана точка останова установлена ​​ранее в строке 18, поэтому self подвергается интроспекции в этой строке. Теперь, когда он доходит до строки 9, он уже посетил .sum в ходе предыдущего самоанализа.

Steven Rumbalski 13.09.2018 19:53

@StevenRumbalski: бинго, отчет об ошибке подтверждает гипотезу: youtrack.jetbrains.net/issue/PY-13006

Martijn Pieters 13.09.2018 19:53
0
17
72
0

Другие вопросы по теме