diff options
author | Raymond Hettinger <python@rcn.com> | 2010-12-01 03:45:41 (GMT) |
---|---|---|
committer | Raymond Hettinger <python@rcn.com> | 2010-12-01 03:45:41 (GMT) |
commit | c79fb0e52d297e0599a37be2652e75e3abc35690 (patch) | |
tree | 512f5b891c76f0035c2eb7d672ba19385e6eb2c6 /Lib/functools.py | |
parent | ed3a7d2d601ce1e65b0bacf24676440631158ec8 (diff) | |
download | cpython-c79fb0e52d297e0599a37be2652e75e3abc35690.zip cpython-c79fb0e52d297e0599a37be2652e75e3abc35690.tar.gz cpython-c79fb0e52d297e0599a37be2652e75e3abc35690.tar.bz2 |
Issue 10593: Adopt Nick's suggestion for an lru_cache with maxsize=None.
Diffstat (limited to 'Lib/functools.py')
-rw-r--r-- | Lib/functools.py | 60 |
1 files changed, 41 insertions, 19 deletions
diff --git a/Lib/functools.py b/Lib/functools.py index 0fbf3cd..d450634 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -119,6 +119,9 @@ _CacheInfo = namedtuple("CacheInfo", "hits misses maxsize currsize") def lru_cache(maxsize=100): """Least-recently-used cache decorator. + If *maxsize* is set to None, the LRU features are disabled and the cache + can grow without bound. + Arguments to the cached function must be hashable. View the cache statistics named tuple (hits, misses, maxsize, currsize) with @@ -136,32 +139,51 @@ def lru_cache(maxsize=100): def decorating_function(user_function, tuple=tuple, sorted=sorted, len=len, KeyError=KeyError): - cache = OrderedDict() # ordered least recent to most recent - cache_popitem = cache.popitem - cache_renew = cache.move_to_end hits = misses = 0 kwd_mark = object() # separates positional and keyword args lock = Lock() - @wraps(user_function) - def wrapper(*args, **kwds): - nonlocal hits, misses - key = args - if kwds: - key += (kwd_mark,) + tuple(sorted(kwds.items())) - try: - with lock: + if maxsize is None: + cache = dict() # simple cache without ordering or size limit + + @wraps(user_function) + def wrapper(*args, **kwds): + nonlocal hits, misses + key = args + if kwds: + key += (kwd_mark,) + tuple(sorted(kwds.items())) + try: result = cache[key] - cache_renew(key) # record recent use of this key hits += 1 - except KeyError: - result = user_function(*args, **kwds) - with lock: - cache[key] = result # record recent use of this key + except KeyError: + result = user_function(*args, **kwds) + cache[key] = result misses += 1 - if len(cache) > maxsize: - cache_popitem(0) # purge least recently used cache entry - return result + return result + else: + cache = OrderedDict() # ordered least recent to most recent + cache_popitem = cache.popitem + cache_renew = cache.move_to_end + + @wraps(user_function) + def wrapper(*args, **kwds): + nonlocal hits, misses + key = args + if kwds: + key += (kwd_mark,) + tuple(sorted(kwds.items())) + try: + with lock: + result = cache[key] + cache_renew(key) # record recent use of this key + hits += 1 + except KeyError: + result = user_function(*args, **kwds) + with lock: + cache[key] = result # record recent use of this key + misses += 1 + if len(cache) > maxsize: + cache_popitem(0) # purge least recently used cache entry + return result def cache_info(): """Report cache statistics""" |