Manu Hack a écrit : > hi all, > > If I have a class A with A.x, A.y, A.z. A.y and A.z are property and > in order to compute the value of them, A.y depends on A.x while A.z > depends on A.y and A.x. If I call A.y, and A.z, the value A.y would > be computed twice. Is there a smart way to avoid that as to A.y will > be recomputed only if A.x has been changed? Now I can define more > variables to keep track of what is changed but when there are more > variables and the dependency becomes more involved it could be very > complicated. Thanks a lot. >
A Q&D solution is to use a local cache (usually a dict with propnames as keys), and have any 'setter' invalidate that cache, ie: def cached_property(fn): propname = fn.__name__ def fget(self): return self._from_cache(propname, fn) def fset(self, val): raise AttributeError("%s.%s is readonly" % (self, propname)) return property(fget, fset) class A(object): def __init__(self, x): self._cache = {} self.x = x def _from_cache(self, name, fn): try: return self._cache[name] except KeyError: val = fn(self) self._cache[name] = val return val def _invalidate_cache(self, *names): for name in names: try: del self._cache[name] except KeyError, e: #print "%s : %s not in %s" % (e, name, self._cache) pass @apply def x(): def fget(self): return self._x def fset(self, x): self._x = x # dependencies here - would be nice to have self._invalidate_cache('y', 'z') return property(**locals()) @cached_property def y(self): return self.x + 2 @cached_property def z(self): return self.x * (self.y / 2.0) The remaining problem is that here, it's x that have the knowledge of who depends on it. This knowledge would be better expressed as a param or the @cached_property decorator and stored somewhere, so that the call to _invalidate cache would take the name of the property itself (here 'x') instead of the list of dependent cached properties. This can be done at least with a custom metaclass - implementation left as an exercice to the reader !-) -- http://mail.python.org/mailman/listinfo/python-list