I have a class A with three attributes a, b, c, where a is computed from b and c (but it is expensive). Moreover, attributes b and c are likely to change over time. I want to make sure that:
- a is cached after it is calculated, and then played from the cache
- If b or c is changed, then the next time it is necessary, it should be recalculated to reflect the change.
The following code works:
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
however, this approach does not seem very good for many reasons:
- setters b and c should know about
- it becomes useless to write and maintain if the dependency tree gets larger
- in the update_a code it may not be obvious what its dependencies are
- this leads to a lot of code duplication.
Is there an abstract way to achieve this that doesn't require me to do all the bookkeeping? Ideally, I would like to have some kind of decorator who tells the property what its dependencies are, so that all accounting information 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 the values ββassigned a, b, c to be immutable. I am most interested in np.arrays and lists, but I would like the code to be reused in many different situations without worrying about variability issues.
source share