Соглашение о хранении len () и sum () как переменной в python - PullRequest
2 голосов
/ 16 марта 2020

Существует ли соглашение о том, когда и как хранить значения len() или sum() в python? Например, если у вас есть класс

class MyClass:

    def __init__(self, single_number = 4, multiple_numbers = [1,2,3]):
        self.single= single_number 
        self.multiple = multiple_numbers

    def info(self):
        print(f"The length of multiple is {len(self.multiple)}")
        print(f"The length of multiple is {len(self.multiple)*4}")
        print(f"The length of multiple is longer than {len(self.multiple)-1}")

if __name__ == "__main__":
    test=MyClass()
    test.info()
    # other stuff
    test.info()

В какой момент вы начнете хранить len(self.multiple) в качестве собственного значения? К счастью, python избавляет от использования len для некоторых задач, таких как for my_numbers in multiple_numbers:, поэтому мне не нужно это только для итераций. Кроме того, значение len равно stati c для экземпляра класса и будет необходимо (вероятно) несколько раз в разных частях времени выполнения, поэтому это не временная переменная , как здесь . В общем, это, кажется, компромисс между (очень маленькими объемами) памяти по сравнению с вычислениями. Та же проблема относится к sum().

Части этих вопросов основаны на мнении, и я рад услышать, что вы об этом думаете, но я в первую очередь ищу соглашение по этому вопросу.

  1. В какой момент, если таковые имеются, len(self.multiple) должен храниться как его собственное значение?
  2. Существует ли соглашение для имени? length_of_multiple_numbers кажется раздутым, но будет описательным.

Ответы [ 2 ]

5 голосов
/ 16 марта 2020

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

def info(self):
    n = len(self.multiple)
    print(f"The length of multiple is {n}")
    print(f"The length of multiple is {n*4}")
    print(f"The length of multiple is longer than {n-1}")

Имена локальных переменных могут быть короткими, поскольку назначение находится на том же экране, что и использование. Я использую свои собственные соглашения, но они, как правило, следуют общим неформальным соглашениям.

Я бы не стал присваивать len(...) атрибуту self, а тем более глобальному.

В основном любой значение, которое многократно используется в функции / методе, является кандидатом на присвоение локальной переменной.

0 голосов
/ 16 марта 2020

Я не уверен, что есть много причин, чтобы оправдать хранилище, если только затраты на вычисления не велики каждый раз. См. Ответ hpaulj.

Однако, если вы действительно этого хотите, вы можете использовать свойство и даже возможно кэшировать его.

class MyList(list):

   @property
   def len_(self):
      return len(self)  #it's a list
or

   _len_ = None

   @property 
   def len_(self):
      if self._len_ is None:
          self._len_ = len(self)
      return self._len_

    def append(self, value):
       self._len_ = None
       super(MyList, self).append(value)

    ...and all other len-modifying methods also need to clear the cache.

Опять же, если вы кэшируете это, вы должны убедиться, что вы сбрасывали кэш каждый раз, когда ваш результат должен измениться. Что также является слабым местом в вашей идее хранения переменной экземпляра - дополнительную сложность убедиться, что у вас нет устаревших данных, вероятно, следует принимать только после того, как вы заявили, что это действительно узкое место в производительности.

(эти проблемы не помогли при использовании изменяемого аргумента по умолчанию для multiple_numbers в вашем примере, кстати). В общем, если расширить это - если ваша сумма / длина зависит от состояния изменяемых элементов, то сохранение / кэширование вычислений - еще худшая идея. т.е. если MyList ссылается на объекты, которые сами имеют длину / сумму, которую нужно агрегировать, то MyList не имеет никакого отношения к кешированию / хранению.

В отношении именования, я бы, вероятно, go для того, что является полу-условное наименование, чтобы избежать дублирования встроенных / обычных имен, то есть добавление _: cls -> cls_, list -> list_.

...