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

This commit is contained in:
Raymond Hettinger 2021-08-02 13:15:45 -05:00 committed by GitHub
parent 28b6dc9dd5
commit 54f185b6d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 31 additions and 15 deletions

View File

@ -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):
class LRU:
def __init__(self, func, maxsize=128):
self.func = func
self.maxsize = maxsize
super().__init__(*args, **kwds)
self.cache = OrderedDict()
def __getitem__(self, key):
value = super().__getitem__(key)
self.move_to_end(key)
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