Consider the following minimal example:
class Foo(object):
def __init__(self):
self.b = self.a = 1
@property
def sum(self):
print 'Recalculating sum'
return self.a + self.b
foo = Foo()
print foo.sum
print foo.sum # Prints 'Recalculating sum' even though neither a or b has changed since previous call
foo.a = 2
print foo.sum # a has been changed to 2 so recalculation is necessary
I would like to memoize sum such that if self.a and self.b doesn't change, then we don't need to keep recalculating the property.
The property should only be recalculated when either self.a or self.b has changed -- is there an simple way to do this?
python3:
from functools import lru_cache as memoized
@property
@memoized(maxsize=1)
def sum(self):
return self.a + self.b
python 3.8
from functools import cached_property
@cached_property
def sum(self):
return self.a + self.b
Use properties for a and b too and clear up your cache in the setters:
class Foo(object):
def __init__(self):
self.a = 1
self.b = 1
@property
def a(self):
return self._a
@a.setter
def a(self, value):
self._a = value
self._clearsum()
@property
def b(self):
return self._b
@b.setter
def b(self, value):
self._b = value
self._clearsum()
def _clearsum(self):
self._sum = None
@property
def sum(self):
if self._sum is None:
self._sum = self.a + self.b
return self._sum
Or if you want something a bit more generic, you can check this too: Storing calculated values in an object
Edit : someone recently suggested adding self._sum = None in __init__ to "avoid an error when accessing sum", but that's actually not necessary - __init__ invokes a.setter, which invokes _clearsum, which sets the _sum attribute, so it's garanteed self._sum will be created whatever.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With