[Python-checkins] bpo-44782: Improve OrderedDict recipe for LRU cache variants (GH-27536)

miss-islington webhook-mailer at python.org
Mon Aug 2 14:38:19 EDT 2021


https://github.com/python/cpython/commit/c6e7c9860d5ac968c7a1073fdbfbd44e0e87f582
commit: c6e7c9860d5ac968c7a1073fdbfbd44e0e87f582
branch: 3.10
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2021-08-02T11:38:14-07:00
summary:

bpo-44782: Improve OrderedDict recipe for LRU cache variants (GH-27536)

(cherry picked from commit 54f185b6d321a6354aef2b2886c766677f487ecb)

Co-authored-by: Raymond Hettinger <rhettinger at users.noreply.github.com>

files:
M Doc/library/collections.rst

diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst
index 2a0bc049f88dd..b1779a5b2382e 100644
--- a/Doc/library/collections.rst
+++ b/Doc/library/collections.rst
@@ -1171,27 +1171,43 @@ original insertion position is changed and moved to the end::
             self.move_to_end(key)
 
 An :class:`OrderedDict` would also be useful for implementing
-variants of :func:`functools.lru_cache`::
+variants of :func:`functools.lru_cache`:
 
-    class LRU(OrderedDict):
-        'Limit size, evicting the least recently looked-up key when full'
+.. testcode::
 
-        def __init__(self, maxsize=128, /, *args, **kwds):
-            self.maxsize = maxsize
-            super().__init__(*args, **kwds)
+    class LRU:
 
-        def __getitem__(self, key):
-            value = super().__getitem__(key)
-            self.move_to_end(key)
+        def __init__(self, func, maxsize=128):
+            self.func = func
+            self.maxsize = maxsize
+            self.cache = OrderedDict()
+
+        def __call__(self, *args):
+            if args in self.cache:
+                value = self.cache[args]
+                self.cache.move_to_end(args)
+                return value
+            value = self.func(*args)
+            if len(self.cache) >= self.maxsize:
+                self.cache.popitem(False)
+            self.cache[args] = value
             return value
 
-        def __setitem__(self, key, value):
-            if key in self:
-                self.move_to_end(key)
-            super().__setitem__(key, value)
-            if len(self) > self.maxsize:
-                oldest = next(iter(self))
-                del self[oldest]
+.. doctest::
+    :hide:
+
+    >>> def square(x):
+    ...     return x ** 2
+    ...
+    >>> s = LRU(square, maxsize=5)
+    >>> actual = [(s(x), s(x)) for x in range(20)]
+    >>> expected = [(x**2, x**2) for x in range(20)]
+    >>> actual == expected
+    True
+    >>> actual = list(s.cache.items())
+    >>> expected = [((x,), x**2) for x in range(15, 20)]
+    >>> actual == expected
+    True
 
 
 :class:`UserDict` objects



More information about the Python-checkins mailing list