.. versionadded:: 3.2
-.. decorator:: lru_cache(maxsize=100)
+.. decorator:: lru_cache(maxsize=100, typed=False)
Decorator to wrap a function with a memoizing callable that saves up to the
*maxsize* most recent calls. It can save time when an expensive or I/O bound
If *maxsize* is set to None, the LRU feature is disabled and the cache
can grow without bound.
+ If *typed* is set to True, function arguments of different types will be
+ cached separately. For example, ``f(3)`` and ``f(3.0)`` will be treated
+ as distinct calls with distinct results.
+
To help measure the effectiveness of the cache and tune the *maxsize*
parameter, the wrapped function is instrumented with a :func:`cache_info`
function that returns a :term:`named tuple` showing *hits*, *misses*,
An `LRU (least recently used) cache
<http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used>`_ works
- best when more recent calls are the best predictors of upcoming calls (for
- example, the most popular articles on a news server tend to change daily).
+ best when the most recent calls are the best predictors of upcoming calls (for
+ example, the most popular articles on a news server tend to change each day).
The cache's size limit assures that the cache does not grow without bound on
long-running processes such as web servers.
.. versionadded:: 3.2
+ .. versionchanged:: 3.3
+ Added the *typed* option.
+
.. decorator:: total_ordering
Given a class defining one or more rich comparison ordering methods, this
_CacheInfo = namedtuple("CacheInfo", "hits misses maxsize currsize")
-def lru_cache(maxsize=100):
+def lru_cache(maxsize=100, typed=False):
"""Least-recently-used cache decorator.
If *maxsize* is set to None, the LRU features are disabled and the cache
can grow without bound.
+ If *typed* is True, arguments of different types will be cached separately.
+ For example, f(3.0) and f(3) will be treated as distinct calls with
+ distinct results.
+
Arguments to the cached function must be hashable.
View the cache statistics named tuple (hits, misses, maxsize, currsize) with
# to allow the implementation to change (including a possible C version).
def decorating_function(user_function,
- tuple=tuple, sorted=sorted, len=len, KeyError=KeyError):
+ *, tuple=tuple, sorted=sorted, map=map, len=len, type=type, KeyError=KeyError):
hits = misses = 0
kwd_mark = (object(),) # separates positional and keyword args
nonlocal hits, misses
key = args
if kwds:
- key += kwd_mark + tuple(sorted(kwds.items()))
+ sorted_items = tuple(sorted(kwds.items()))
+ key += kwd_mark + sorted_items
+ if typed:
+ key += tuple(map(type, args))
+ if kwds:
+ key += tuple(type(v) for k, v in sorted_items)
try:
result = cache[key]
hits += 1
nonlocal hits, misses
key = args
if kwds:
- key += kwd_mark + tuple(sorted(kwds.items()))
+ sorted_items = tuple(sorted(kwds.items()))
+ key += kwd_mark + sorted_items
+ if typed:
+ key += tuple(map(type, args))
+ if kwds:
+ key += tuple(type(v) for k, v in sorted_items)
with lock:
try:
result = cache[key]
def purge():
"Clear the regular expression caches"
- _compile_typed.cache_clear()
+ _compile.cache_clear()
_compile_repl.cache_clear()
def template(pattern, flags=0):
_pattern_type = type(sre_compile.compile("", 0))
+@functools.lru_cache(maxsize=500, typed=True)
def _compile(pattern, flags):
- return _compile_typed(type(pattern), pattern, flags)
-
-@functools.lru_cache(maxsize=500)
-def _compile_typed(text_bytes_type, pattern, flags):
# internal: compile pattern
if isinstance(pattern, _pattern_type):
if flags:
with self.assertRaises(IndexError):
func(15)
+ def test_lru_with_types(self):
+ for maxsize in (None, 100):
+ @functools.lru_cache(maxsize=maxsize, typed=True)
+ def square(x):
+ return x * x
+ self.assertEqual(square(3), 9)
+ self.assertEqual(type(square(3)), type(9))
+ self.assertEqual(square(3.0), 9.0)
+ self.assertEqual(type(square(3.0)), type(9.0))
+ self.assertEqual(square(x=3), 9)
+ self.assertEqual(type(square(x=3)), type(9))
+ self.assertEqual(square(x=3.0), 9.0)
+ self.assertEqual(type(square(x=3.0)), type(9.0))
+ self.assertEqual(square.cache_info().hits, 4)
+ self.assertEqual(square.cache_info().misses, 4)
+
def test_main(verbose=None):
test_classes = (
TestPartial,
Library
-------
+- Issue #13227: functools.lru_cache() now has a option to distinguish
+ calls with different argument types.
+
- Issue #6090: zipfile raises a ValueError when a document with a timestamp
earlier than 1980 is provided. Patch contributed by Petri Lehtinen.