summaryrefslogtreecommitdiffstats
path: root/Doc/library
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2021-08-02 18:15:45 (GMT)
committerGitHub <noreply@github.com>2021-08-02 18:15:45 (GMT)
commit54f185b6d321a6354aef2b2886c766677f487ecb (patch)
treefb4d541760adda91689b6357c93a894d444d2c6f /Doc/library
parent28b6dc9dd5d1ce6f8aff7e06d4ef9afdc2bc8332 (diff)
downloadcpython-54f185b6d321a6354aef2b2886c766677f487ecb.zip
cpython-54f185b6d321a6354aef2b2886c766677f487ecb.tar.gz
cpython-54f185b6d321a6354aef2b2886c766677f487ecb.tar.bz2
bpo-44782: Improve OrderedDict recipe for LRU cache variants (GH-27536)
Diffstat (limited to 'Doc/library')
-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 2a0bc04..b1779a5 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