diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -121,12 +121,15 @@ _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. + Arguments to the cached function must be hashable. View the cache statistics named tuple (hits, misses, maxsize, currsize) with @@ -142,7 +145,7 @@ # 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, KeyError=KeyError): hits = misses = 0 kwd_mark = (object(),) # separates positional and keyword args @@ -157,6 +160,8 @@ key = args if kwds: key += kwd_mark + tuple(sorted(kwds.items())) + if typed: + key += tuple(map(type, key)) try: result = cache[key] hits += 1 @@ -178,6 +183,8 @@ key = args if kwds: key += kwd_mark + tuple(sorted(kwds.items())) + if typed: + key += tuple(map(type, key)) with lock: try: result = cache[key] diff --git a/Lib/re.py b/Lib/re.py --- a/Lib/re.py +++ b/Lib/re.py @@ -207,7 +207,7 @@ def purge(): "Clear the regular expression caches" - _compile_typed.cache_clear() + _compile.cache_clear() _compile_repl.cache_clear() def template(pattern, flags=0): @@ -253,11 +253,8 @@ _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: diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -734,6 +734,16 @@ with self.assertRaises(IndexError): func(15) + def test_lru_with_types(self): + @functools.lru_cache(maxsize=None, typed=True) + def square(x): + return x * x + self.assertEqual(square(3), 9) + self.assertEqual(square(3.0), 9.0) + self.assertEqual(type(square(3.0)), type(9.0)) + self.assertEqual(square.cache_info().hits, 1) + self.assertEqual(square.cache_info().misses, 2) + def test_main(verbose=None): test_classes = ( TestPartial,