import itertools class LRUDict(object): def __init__(self, n): self.n = n self.inner = {} self.counter = itertools.count() def get(self, key, default=None): if key in self.inner: x, value = self.inner[key] self.inner[key] = self.counter.next(), value return value return default def __setitem__(self, key, value): self.inner[key] = self.counter.next(), value while len(self.inner) > self.n: self.inner.pop(min(self.inner, key=lambda k: self.inner[k][0])) _nothing = object() def memoize_with_backing(backing, has_inverses=set()): def a(f): def b(*args): res = backing.get((f, args), _nothing) if res is not _nothing: return res res = f(*args) backing[(f, args)] = res for inverse in has_inverses: backing[(inverse, args[:-1] + (res,))] = args[-1] return res return b return a def memoize(f): return memoize_with_backing({})(f)