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.
len(self.multiple)
be stored as its own value?length_of_multiple_numbers
seems bloated but would be descriptive.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_
.