Convention for storing len() and sum() as variable in python

Finn :

Is there a convention of when and how to store values of len() or sum() in python? To provide an example, if you have a Class

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()

At what point would you start storing len(self.multiple) as its own value? Thankfully, python spares the use of len for some tasks like for my_numbers in multiple_numbers: so I wouldn't need it just for iterations. In addition, the value of len is static for the instance of the class and will be needed (probably) multiple times at different parts within the runtime, so it is not a temporary variable like here. In general, this seems to be a tradeoff between (very small amounts) of memory vs computation. The same issue applies to sum().

Parts of these questions are opinion-based, and I am happy to hear what you think about it, but I am looking primarily for a convention on this.

  1. At what point, if any, should len(self.multiple) be stored as its own value?
  2. Is there a convention for the name? length_of_multiple_numbers seems bloated but would be descriptive.
JL Peyret :

I am not convinced that there is much to justify storage, unless the computation cost is heavy each time. See hpaulj's answer.

However, if you really really wanted to, you could use a property and even possibly cache it.

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.

Again, if you cache it, you need to make sure you reset the cache each time your result should change. Which is also the weak point with your idea of storing on an instance variable - the additional complexity to make sure you don't have outdated data should probably only be accepted once you've profiled that this is indeed a performance bottleneck.

(these issues are not helped by using a mutable default argument for multiple_numbers in your example, btw). To generally extend that - if your sum/len depends on the state of mutable items, then storing/caching the computations is an even worse idea. i.e. if MyList refers to objects that themselves have a len/sum which needs to be aggregated, then MyList has no business whatsoever caching/storing.

Naming-wise, I'd probably go for what's a semi-convention naming to avoid shadowing built-ins/conventional names i.e. adding a _: cls -> cls_, list -> list_.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=297489&siteId=1