'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 1:[1]

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

Solution 2:[2]

there is a module that does this. Pypi link here: https://pypi.org/project/memoized-property/ For the above code I have this with using the module:

In [2]: from memoized_property import memoized_property                                                                                                       

In [3]: class test():  
   ...:         def __init__(self):  
   ...:             self.a = 0  
   ...:             self.b = 0  
   ...:        @memoized_property  
   ...:        def sum(self):  
   ...:           print('calculating...')  
   ...:           return self.a + self.b  

In [4]: t=test()                                                                                                                                              

calculating...
In [5]: t.sum                                                                                                                                                 
Out[5]: 0

In [7]: t.a=5                                                                                                                                                 

In [8]: t.sum                                                                                                                                                 
Out[8]: 0

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sam Watkins
Solution 2 AthulMuralidhar