import types def cachedmethod(function): return types.MethodType(Memoize(function), None) class Memoize: def __init__(self,function): self._cache = {} self._callable = function def __call__(self, *args, **kwds): cache = self._cache key = self._getKey(*args,**kwds) try: return cache[key] except KeyError: cachedValue = cache[key] = self._callable(*args,**kwds) return cachedValue def _getKey(self,*args,**kwds): return kwds and (args, ImmutableDict(kwds)) or args class ImmutableDict(dict): '''A hashable dict.''' def __init__(self,*args,**kwds): dict.__init__(self,*args,**kwds) def __setitem__(self,key,value): raise NotImplementedError, "dict is immutable" def __delitem__(self,key): raise NotImplementedError, "dict is immutable" def clear(self): raise NotImplementedError, "dict is immutable" def setdefault(self,k,default=None): raise NotImplementedError, "dict is immutable" def popitem(self): raise NotImplementedError, "dict is immutable" def update(self,other): raise NotImplementedError, "dict is immutable" def __hash__(self): return hash(tuple(self.iteritems())) if __name__ == '__main__': from math import sqrt,log,sin,cos class Example: def __init__(self,x,y): # self._x and self._y should not be changed after initialization self._x = x self._y = y @cachedmethod def computeSomething(self, alpha, beta): w = log(alpha) * sqrt(self._x * alpha + self._y * beta) z = log(beta) * sqrt(self._x * beta + self._y * alpha) return sin(z) / cos(w)