summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2021-08-02 18:37:42 (GMT)
committerGitHub <noreply@github.com>2021-08-02 18:37:42 (GMT)
commitc50a672eebb16cf778d9a3b22b72d506c3f54ced (patch)
tree749304785b07d03825f161d0587fb19d3af6f72e
parente0d599fa48032eb7b8d837f8412bbca72b6ad820 (diff)
downloadcpython-c50a672eebb16cf778d9a3b22b72d506c3f54ced.zip
cpython-c50a672eebb16cf778d9a3b22b72d506c3f54ced.tar.gz
cpython-c50a672eebb16cf778d9a3b22b72d506c3f54ced.tar.bz2
bpo-44782: Improve OrderedDict recipe for LRU cache variants (GH-27536) (GH-27567)
-rw-r--r--Doc/library/collections.rst48
1 files changed, 32 insertions, 16 deletions
diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst
index 000015b..e00b75f 100644
--- a/Doc/library/collections.rst
+++ b/Doc/library/collections.rst
@@ -1149,27 +1149,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