Проверьте, была ли определена переменная класса

Я имею дело со сценарием, где у меня есть класс Python Foo. Фу, между прочим, делает много больших вычислений, которые я бы не делал, если бы не требовал. Итак, когда я определяю метод получения для одного из этих больших вычислений, как мне убедиться, что метод, соответствующий вычислению (здесь bigcalculation()), уже запущен?

class Foo:
    def __init__(self):
        #initialize some stuff
    def bigcalculation(self):
         #perform calculation
         self.big_calc_result=[big list of numbers];

    def get_big_calc_result(self):
        if hasattr(self,'big_calc_result')==False:
            self.bigcalculations();
        return sef.big_calc_result;

Если его запустить один раз, я не хочу, чтобы он снова запускался. и я не хочу, чтобы вызывающий абонент отслеживал, запустился ли он один раз или нет.

Теперь я делаю это с помощью функции hasattr(), как описано выше, но я думаю, что это действительно ужасный способ сделать это. Есть ли более элегантный способ сделать это?

Альтернативой, которую я могу придумать, является определение в моей функции init() всех переменных, которые я бы когда-либо использовал в классе, как пустой список. Затем проверьте, является ли big_calc_result пустым списком или нет, чтобы определить, выполнялся ли self.bigcalculation(). Это лучший подход?

связанный вопрос:Python позволяет мне определять переменные на лету в классе. Но разве это плохая практика программирования?

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

def get_big_calc_result(self):
    try:
        return self.big_calc_result;
    except AttributeError:
        self.bigcalculations();
        return self.big_calc_result;

Ответы на этот вопрос полезны: проверка существования члена в Python

1 ответ

Решение

Вы можете запомнить результат и сохранить его как свойство:

class Foo(object):
    def __init__(self):
        self._big_calc_result = None

    @property
    def big_calc_result(self):
        if self._big_calc_result is not None:
            return self._big_calc_result
        else:
            self._big_calc_result = self.big_calc_run()
            return self._big_calc_result 

    def big_calc_run(self):
        time.sleep(10)  # Takes a long time ...

Теперь вы просто инициализируете класс и получаете результат:

f = Foo()
x = f.big_calc_result
y = f.bic_calc_result  # Look mom, this happened really quick

Конечно, вам не нужно использовать свойство, если оно менее интуитивно понятно, и вы можете изменить здесь все в соответствии с API, который вы пытаетесь предоставить. Настоящий смысл заключается в кешировании результата в переменную с префиксом подчеркивания, которая гласит: "Это деталь реализации - если вы возитесь с ней, вы заслуживаете того, чтобы ваш код сломался в какой-то момент в будущем".

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