From 987d2519c20ae08d75f0bb7dafdd326294ab59a9 Mon Sep 17 00:00:00 2001 From: Jon Huber Date: Mon, 27 Jun 2022 12:32:11 -0500 Subject: [PATCH] Introduce args slicing for trimming cache key --- functools32/functools32.py | 24 +++++++++++++++++--- test_functools32.py | 46 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/functools32/functools32.py b/functools32/functools32.py index c44551f..8c611ec 100644 --- a/functools32/functools32.py +++ b/functools32/functools32.py @@ -334,7 +334,7 @@ def __ne__(self, other): _CacheInfo = namedtuple("CacheInfo", "hits misses maxsize currsize") -def lru_cache(maxsize=100): +def lru_cache(maxsize=100, key_arg_slice_start=None, key_arg_slice_stop=None): """Least-recently-used cache decorator. If *maxsize* is set to None, the LRU features are disabled and the cache @@ -366,7 +366,16 @@ def decorating_function(user_function, @wraps(user_function) def wrapper(*args, **kwds): - key = args + + if key_arg_slice_start and key_arg_slice_stop: + key = args[key_arg_slice_start:key_arg_slice_stop] + elif key_arg_slice_start: + key = args[key_arg_slice_start:] + elif key_arg_slice_stop: + key = args[:key_arg_slice_stop] + else: + key = args + if kwds: key += kwd_mark + tuple(sorted(kwds.items())) try: @@ -386,7 +395,16 @@ def wrapper(*args, **kwds): @wraps(user_function) def wrapper(*args, **kwds): - key = args + + if key_arg_slice_start and key_arg_slice_stop: + key = args[key_arg_slice_start:key_arg_slice_stop] + elif key_arg_slice_start: + key = args[key_arg_slice_start:] + elif key_arg_slice_stop: + key = args[:key_arg_slice_stop] + else: + key = args + if kwds: key += kwd_mark + tuple(sorted(kwds.items())) with lock: diff --git a/test_functools32.py b/test_functools32.py index b709f37..b9afc6b 100644 --- a/test_functools32.py +++ b/test_functools32.py @@ -637,6 +637,52 @@ def func(i): with self.assertRaises(IndexError): func(15) + def test_lru_slice(self): + def orig(o, x, y): + return 3*x+y + f = functools.lru_cache(maxsize=20, key_arg_slice_start=1)(orig) + hits, misses, maxsize, currsize = f.cache_info() + self.assertEqual(maxsize, 20) + self.assertEqual(currsize, 0) + self.assertEqual(hits, 0) + self.assertEqual(misses, 0) + + obj1 = "object1" + obj2 = "object2" + obj3 = "object3" + f(obj1, 1, 1) + f(obj2, 1, 1) + f(obj3, 1, 1) + + hits, misses, maxsize, currsize = f.cache_info() + self.assertEqual(maxsize, 20) + self.assertEqual(currsize, 1) + self.assertEqual(hits, 2) + self.assertEqual(misses, 1) + + def test_lru_slice_no_max(self): + def orig(o, x, y): + return 3*x+y + f = functools.lru_cache(maxsize=None, key_arg_slice_start=1)(orig) + hits, misses, maxsize, currsize = f.cache_info() + self.assertEqual(maxsize, None) + self.assertEqual(currsize, 0) + self.assertEqual(hits, 0) + self.assertEqual(misses, 0) + + obj1 = "object1" + obj2 = "object2" + obj3 = "object3" + f(obj1, 1, 1) + f(obj2, 1, 1) + f(obj3, 1, 1) + + hits, misses, maxsize, currsize = f.cache_info() + self.assertEqual(maxsize, None) + self.assertEqual(currsize, 1) + self.assertEqual(hits, 2) + self.assertEqual(misses, 1) + class TestOrderedDict(unittest.TestCase): def test_move_to_end(self): od = OrderedDict.fromkeys('abcde')