I have a class A with three attributes a,b,c, where a is calculated from b and c (but this is expensive). Moreover, attributes b and c are likely to change over times. I want to make sure that:
- a is cached once it is calculated and then reproduced from cache
- if b or c change then the next time a is needed it must be recomputed to reflect the change
the following code seems to work:
class A():
def __init__(self, b, c):
self._a = None
self._b = b
self._c = c
@property
def a(self):
if is None:
self.update_a()
return self._a
def update_a(self):
"""
compute a from b and c
"""
print('this is expensive')
self._a = self.b + 2*self.c
@property
def b(self):
return self._b
@b.setter
def b(self, value):
self._b = value
self._a = None #make sure a is recalculated before its next use
@property
def c(self):
return self._c
@c.setter
def c(self, value):
self._c = value
self._a = None #make sure a is recalculated before its next use
however this approach does not seem very good for many reasons:
- the setters of b and c needs to know about a
- it becomes a mess to write and maintain if the dependency-tree grows larger
- it might not be apparent in the code of update_a what its dependencies are
- it leads to a lot of code duplication
Is there an abstract way to achieve this that does not require me to do all the bookkeeping myself? Ideally, I would like to have some sort of decorator which tells the property what its dependencies are so that all the bookkeeping happens under the hood.
I would like to write:
@cached_property_depends_on('b', 'c')
def a(self):
return self.b+2*self.c
or something like that.
EDIT: I would prefer solutions that do not require that the values assigned to a,b,c be immutable. I am mostly interested in np.arrays and lists but I would like the code to be reusable in many different situations without having to worry about mutability issues.