Search code examples
pythonpropertiesmemoization

How to memoize a property in Python?


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?


Solution

  • 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.