property question
Bruno Desthuilliers
bruno.42.desthuilliers at wtf.websiteburo.oops.com
Tue Oct 9 07:55:47 EDT 2007
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 !-)
More information about the Python-list
mailing list