diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2021-08-02 18:37:42 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-02 18:37:42 (GMT) |
commit | c50a672eebb16cf778d9a3b22b72d506c3f54ced (patch) | |
tree | 749304785b07d03825f161d0587fb19d3af6f72e | |
parent | e0d599fa48032eb7b8d837f8412bbca72b6ad820 (diff) | |
download | cpython-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.rst | 48 |
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 |