summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2015-07-07 00:25:20 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2015-08-16 12:50:39 -0700
commit92f398a897949e3b586abc38a934ae9d5cf1163c (patch)
tree8229c4b7df49ae4feb9d1aa94d6bd8981e243b05
parentda98b07624e2403807166e8a9d0dac3752f75c0f (diff)
downloadspack-92f398a897949e3b586abc38a934ae9d5cf1163c.tar.gz
spack-92f398a897949e3b586abc38a934ae9d5cf1163c.tar.bz2
spack-92f398a897949e3b586abc38a934ae9d5cf1163c.tar.xz
spack-92f398a897949e3b586abc38a934ae9d5cf1163c.zip
Better `@memoized` decorator.
-rw-r--r--lib/spack/llnl/util/lang.py33
1 files changed, 25 insertions, 8 deletions
diff --git a/lib/spack/llnl/util/lang.py b/lib/spack/llnl/util/lang.py
index 9e1bef18ca..be6dad867e 100644
--- a/lib/spack/llnl/util/lang.py
+++ b/lib/spack/llnl/util/lang.py
@@ -26,6 +26,7 @@ import os
import re
import sys
import functools
+import collections
import inspect
# Ignore emacs backups when listing modules
@@ -170,16 +171,32 @@ def has_method(cls, name):
return False
-def memoized(obj):
+class memoized(object):
"""Decorator that caches the results of a function, storing them
in an attribute of that function."""
- cache = obj.cache = {}
- @functools.wraps(obj)
- def memoizer(*args, **kwargs):
- if args not in cache:
- cache[args] = obj(*args, **kwargs)
- return cache[args]
- return memoizer
+ def __init__(self, func):
+ self.func = func
+ self.cache = {}
+
+
+ def __call__(self, *args):
+ if not isinstance(args, collections.Hashable):
+ # Not hashable, so just call the function.
+ return self.func(*args)
+
+ if args not in self.cache:
+ self.cache[args] = self.func(*args)
+ return self.cache[args]
+
+
+ def __get__(self, obj, objtype):
+ """Support instance methods."""
+ return functools.partial(self.__call__, obj)
+
+
+ def clear(self):
+ """Expunge cache so that self.func will be called again."""
+ self.cache.clear()
def list_modules(directory, **kwargs):