From ab9c7afee9f7e99050854c0dc7793e9180975dbb Mon Sep 17 00:00:00 2001 From: Andrew Grangaard Date: Thu, 28 Oct 2021 19:24:11 -0700 Subject: [PATCH 1/5] makes LRUCache constructor concrete --- other/least_recently_used.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/other/least_recently_used.py b/other/least_recently_used.py index d0e27efc6dc8..4a52fb6be3f5 100644 --- a/other/least_recently_used.py +++ b/other/least_recently_used.py @@ -1,5 +1,4 @@ import sys -from abc import abstractmethod from collections import deque @@ -10,7 +9,6 @@ class LRUCache: key_reference_map = object() # References of the keys in cache _MAX_CAPACITY: int = 10 # Maximum capacity of cache - @abstractmethod def __init__(self, n: int): """Creates an empty store and map for the keys. The LRUCache is set the size n. @@ -54,6 +52,7 @@ def display(self): if __name__ == "__main__": + lru_cache = LRUCache(4) lru_cache.refer(1) lru_cache.refer(2) From bec5109abfb526a58f181ce1feea360da187f8aa Mon Sep 17 00:00:00 2001 From: Andrew Grangaard Date: Thu, 28 Oct 2021 19:50:30 -0700 Subject: [PATCH 2/5] fixes bug in dq_removal + deque.remove() operates by value not index --- other/least_recently_used.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/other/least_recently_used.py b/other/least_recently_used.py index 4a52fb6be3f5..e90f5e5dbade 100644 --- a/other/least_recently_used.py +++ b/other/least_recently_used.py @@ -33,12 +33,7 @@ def refer(self, x): last_element = self.dq_store.pop() self.key_reference_map.remove(last_element) else: - index_remove = 0 - for idx, key in enumerate(self.dq_store): - if key == x: - index_remove = idx - break - self.dq_store.remove(index_remove) + self.dq_store.remove(x) self.dq_store.appendleft(x) self.key_reference_map.add(x) From 9167c239c5bf58b4fbb643801fd6e2bd6de57865 Mon Sep 17 00:00:00 2001 From: Andrew Grangaard Date: Thu, 28 Oct 2021 19:55:09 -0700 Subject: [PATCH 3/5] [mypy] Annotates other/least_recently_used over generic type + clean-up: rename key_reference to match type. --- other/least_recently_used.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/other/least_recently_used.py b/other/least_recently_used.py index e90f5e5dbade..43647da72d89 100644 --- a/other/least_recently_used.py +++ b/other/least_recently_used.py @@ -1,20 +1,23 @@ import sys from collections import deque +from typing import Generic, TypeVar +T = TypeVar("T") -class LRUCache: + +class LRUCache(Generic[T]): """Page Replacement Algorithm, Least Recently Used (LRU) Caching.""" - dq_store = object() # Cache store of keys - key_reference_map = object() # References of the keys in cache + dq_store: deque[T] # Cache store of keys + key_reference: set[T] # References of the keys in cache _MAX_CAPACITY: int = 10 # Maximum capacity of cache - def __init__(self, n: int): + def __init__(self, n: int) -> None: """Creates an empty store and map for the keys. The LRUCache is set the size n. """ self.dq_store = deque() - self.key_reference_map = set() + self.key_reference = set() if not n: LRUCache._MAX_CAPACITY = sys.maxsize elif n < 0: @@ -22,23 +25,23 @@ def __init__(self, n: int): else: LRUCache._MAX_CAPACITY = n - def refer(self, x): + def refer(self, x: T) -> None: """ Looks for a page in the cache store and adds reference to the set. Remove the least recently used key if the store is full. Update store to reflect recent access. """ - if x not in self.key_reference_map: + if x not in self.key_reference: if len(self.dq_store) == LRUCache._MAX_CAPACITY: last_element = self.dq_store.pop() - self.key_reference_map.remove(last_element) + self.key_reference.remove(last_element) else: self.dq_store.remove(x) self.dq_store.appendleft(x) - self.key_reference_map.add(x) + self.key_reference.add(x) - def display(self): + def display(self) -> None: """ Prints all the elements in the store. """ From e0971932dca7ad65445f14e9dd3e33fad85ce284 Mon Sep 17 00:00:00 2001 From: Andrew Grangaard Date: Thu, 28 Oct 2021 19:58:48 -0700 Subject: [PATCH 4/5] [mypy] updates example to demonstrate LRUCache with complex type --- other/least_recently_used.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/other/least_recently_used.py b/other/least_recently_used.py index 43647da72d89..2b04cc6e5350 100644 --- a/other/least_recently_used.py +++ b/other/least_recently_used.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys from collections import deque from typing import Generic, TypeVar @@ -51,11 +53,11 @@ def display(self) -> None: if __name__ == "__main__": - lru_cache = LRUCache(4) - lru_cache.refer(1) + lru_cache: LRUCache[str | int] = LRUCache(4) + lru_cache.refer("A") lru_cache.refer(2) lru_cache.refer(3) - lru_cache.refer(1) + lru_cache.refer("A") lru_cache.refer(4) lru_cache.refer(5) lru_cache.display() From 045f54b93c7f1adce41bf103dc3242a165197968 Mon Sep 17 00:00:00 2001 From: Andrew Grangaard Date: Thu, 28 Oct 2021 21:59:25 -0700 Subject: [PATCH 5/5] Adds doctest to other/least_recently_used --- other/least_recently_used.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/other/least_recently_used.py b/other/least_recently_used.py index 2b04cc6e5350..cb692bb1b1c0 100644 --- a/other/least_recently_used.py +++ b/other/least_recently_used.py @@ -8,7 +8,27 @@ class LRUCache(Generic[T]): - """Page Replacement Algorithm, Least Recently Used (LRU) Caching.""" + """ + Page Replacement Algorithm, Least Recently Used (LRU) Caching. + + >>> lru_cache: LRUCache[str | int] = LRUCache(4) + >>> lru_cache.refer("A") + >>> lru_cache.refer(2) + >>> lru_cache.refer(3) + + >>> lru_cache + LRUCache(4) => [3, 2, 'A'] + + >>> lru_cache.refer("A") + >>> lru_cache + LRUCache(4) => ['A', 3, 2] + + >>> lru_cache.refer(4) + >>> lru_cache.refer(5) + >>> lru_cache + LRUCache(4) => [5, 4, 'A', 3] + + """ dq_store: deque[T] # Cache store of keys key_reference: set[T] # References of the keys in cache @@ -50,8 +70,14 @@ def display(self) -> None: for k in self.dq_store: print(k) + def __repr__(self) -> str: + return f"LRUCache({self._MAX_CAPACITY}) => {list(self.dq_store)}" + if __name__ == "__main__": + import doctest + + doctest.testmod() lru_cache: LRUCache[str | int] = LRUCache(4) lru_cache.refer("A") @@ -61,3 +87,6 @@ def display(self) -> None: lru_cache.refer(4) lru_cache.refer(5) lru_cache.display() + + print(lru_cache) + assert str(lru_cache) == "LRUCache(4) => [5, 4, 'A', 3]"