diff options
author | Adrien Di Mascio <Adrien.DiMascio@logilab.fr> | 2011-10-10 15:14:47 +0200 |
---|---|---|
committer | Adrien Di Mascio <Adrien.DiMascio@logilab.fr> | 2011-10-10 15:14:47 +0200 |
commit | dca0bc8ab45d0fba854e3e0cb103ee47aa1baef0 (patch) | |
tree | 3bae703bc59900c658515fd255dd235aba037e37 /decorators.py | |
parent | a1af8ab0eed9033e955bf69564e0c82fbb3cb30b (diff) | |
download | logilab-common-dca0bc8ab45d0fba854e3e0cb103ee47aa1baef0.tar.gz |
[decorators] provide a @cachedproperty decorator
Diffstat (limited to 'decorators.py')
-rw-r--r-- | decorators.py | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/decorators.py b/decorators.py index 91d7492..2bce3e8 100644 --- a/decorators.py +++ b/decorators.py @@ -116,6 +116,45 @@ def cached(callableobj=None, keyarg=None, **kwargs): else: return decorator(callableobj) + +class cachedproperty(object): + """ Provides a cached property equivalent to the stacking of + @cached and @property, but more efficient. + + After first usage, the <property_name> becomes part of the object's + __dict__. Doing: + + del obj.<property_name> empties the cache. + + Idea taken from the pyramid_ framework and the mercurial_ project. + + .. _pyramid: http://pypi.python.org/pypi/pyramid + .. _mercurial: http://pypi.python.org/pypi/Mercurial + """ + __slots__ = ('wrapped',) + + def __init__(self, wrapped): + try: + wrapped.__name__ + except AttributeError: + raise TypeError('%s must have a __name__ attribute' % + wrapped) + self.wrapped = wrapped + + @property + def __doc__(self): + doc = getattr(self.wrapped, '__doc__', None) + return ('<wrapped by the cachedproperty decorator>%s' + % ('\n%s' % doc if doc else '')) + + def __get__(self, inst, objtype=None): + if inst is None: + return self + val = self.wrapped(inst) + setattr(inst, self.wrapped.__name__, val) + return val + + def get_cache_impl(obj, funcname): cls = obj.__class__ member = getattr(cls, funcname) |