summaryrefslogtreecommitdiffstats
path: root/Lib/functools.py
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2010-12-01 03:45:41 (GMT)
committerRaymond Hettinger <python@rcn.com>2010-12-01 03:45:41 (GMT)
commitc79fb0e52d297e0599a37be2652e75e3abc35690 (patch)
tree512f5b891c76f0035c2eb7d672ba19385e6eb2c6 /Lib/functools.py
parented3a7d2d601ce1e65b0bacf24676440631158ec8 (diff)
downloadcpython-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.py60
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"""