forked from TheAlgorithms/Python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlru_cache_pythonic.py
107 lines (95 loc) · 3.35 KB
/
lru_cache_pythonic.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
from typing import Any, Hashable
'''
The following implementation of LRU Cache is one of the most elegant pythonic implementations.
It only uses the in-built python dictionary (https://docs.python.org/3/library/stdtypes.html#typesmapping). This works because
the Python dictionary maintains the order of insertion of keys and ensures O(1) operations on insert, delete and access.
'''
class LRUCache(dict):
def __init__(self, capacity : int)->None:
'''
Initialize an LRU Cache with given capacity.
capacity : int -> the capacity of the LRU Cache
>>> cache = LRUCache(2)
>>> cache
{}
'''
self.remaining:int = capacity
def get(self, key:Hashable)->Any:
'''
This method gets the value associated with the key.
key : Hashable -> a hashable object that is mapped to a value inside of the LRU cache.
returns -> value : Any -> any object that is stored as a value inside of the LRU cache.
>>> cache = LRUCache(2)
>>> cache.put(1,1)
>>> cache.get(1)
1
>>> cache.get(2)
Traceback (most recent call last):
...
KeyError: '2 not found.'
'''
if key not in self:
raise KeyError(f"{key} not found.")
val = self.pop(key) # Pop the key-value and re-insert to maintain the order
self[key] = val
return val
def put(self, key:Hashable, value:Any)->None:
'''
This method puts the value associated with the key provided inside of the LRU cache.
key : Hashable -> a hashable object that is mapped to a value inside of the LRU cache.
value: Any -> any object that is to be associated with the key inside of the LRU cache.
>>> cache = LRUCache(2)
>>> cache.put(3,3)
>>> cache
{3: 3}
>>> cache.put(2,2)
>>> cache
{3: 3, 2: 2}
'''
# To pop the last value inside of the LRU cache
if key in self:
self.pop(key)
self[key] = value
return
if self.remaining > 0: self.remaining -= 1
# To pop the least recently used item from the dictionary
else: self.pop(next(iter(self)))
self[key] = value
def main()->None:
'''Example test case with LRU_Cache of size 2
>>> main()
1
Key=2 not found in cache
Key=1 not found in cache
3
4
'''
cache = LRUCache(2) # Creates an LRU cache with size 2
cache.put(1,1) # cache = {1:1}
cache.put(2,2) # cache = {1:1, 2:2}
try:
print(cache.get(1)) # Prints 1
except KeyError:
print("Key not found in cache")
cache.put(3,3) # cache = {1:1, 3:3} key=2 is evicted because it wasn't used recently
try:
print(cache.get(2))
except KeyError:
print("Key=2 not found in cache") # Prints key not found
cache.put(4,4) # cache = {4:4, 3:3} key=1 is evicted because it wasn't used recently
try:
print(cache.get(1))
except KeyError:
print("Key=1 not found in cache") # Prints key not found
try:
print(cache.get(3)) # Prints value 3
except KeyError:
print("Key not found in cache")
try:
print(cache.get(4)) # Prints value 4
except KeyError:
print("Key not found in cache")
if __name__ == '__main__':
import doctest
doctest.testmod()
main()