I have been trying to implement my own version of an LRU cache that deletes the least recently used value after a short period of time. I am using the code I found at (https://www.kunxi.org/blog/2014/05/lru-cache-in-python/) as a template.
(This the code found there so you don't have to open it):
class LRUCache:
def __init__(self, capacity):
self.capacity = capacity
self.tm = 0
self.cache = {}
self.lru = {}
def get(self, key):
if key in self.cache:
self.lru[key] = self.tm
self.tm += 1
return self.cache[key]
return -1
def set(self, key, value):
if len(self.cache) >= self.capacity:
# find the LRU entry
old_key = min(self.lru.keys(), key=lambda k:self.lru[k])
self.cache.pop(old_key)
self.lru.pop(old_key)
self.cache[key] = value
self.lru[key] = self.tm
self.tm += 1
This code works as intended
cache = LRUCache(2)
cache.set(1, 20)
cache.set(2, 40)
print(cache.get(2))
40
but for this case it returns an error:
for i in cache:
print(i)
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: 'LRUCache' object is not iterable
the output I expected is:
(1, 20)
(2, 40)
Why doesn't it work for this case and how do I get it to print my expected output?
Also I want to delete values that have been in the cache for long periods of time automatically, I have experimented but couldn't accomplish this. I tried modifying the code such that:
from time import time
class LRUCache:
def __init__(self, capacity, expiry_time):
self.capacity = capacity
self.expiry_time = expiry_time
self.expired = False
self.tm = 0
self.cache = {}
self.lru = {}
def get(self, key):
if key in self.cache:
self.lru[key] = self.tm
self.tm += 1
return self.cache[key]
return -1
if self.expired is False:
return (self.expires_at < time())
if self.expires_at < time():
return -1
def set(self, key, value):
if len(self.cache) >= self.capacity:
# find the LRU entry
old_key = min(self.lru.keys(), key=lambda k:self.lru[k])
self.cache.pop(old_key)
self.lru.pop(old_key)
self.cache[key] = value
self.lru[key] = self.tm
self.tm += 1
However even with my changes, when I try to 'get' values, they do not return -1 when it is past the expiry time. How do I get around this?
Your cache
object is getting the error object is not iterable
because you haven't implemented any ways for it to be iterable.
This is perhaps better left to another question: Build a Basic Python Iterator
With a quote from this answer:
There are four ways to build an iterative function:
- ...
- ...
- create an iterator (defines
__iter__
and__next__
(ornext
in Python 2.x))- create a function that Python can iterate over on its own (defines
__getitem__
)
For your changes, you have placed them at the end of the function, so the default functionality is always happening first. This need re-arraging as so:
class LRUCache:
def __init__(self, capacity, expiry_time):
...
def get(self, key):
if self.expired is False:
return (self.expires_at < time())
if self.expires_at < time():
return -1
if key in self.cache:
self.lru[key] = self.tm
self.tm += 1
return self.cache[key]
return -1
def set(self, key, value):
...
However, there are a couple of other immediate problems with the implementation:
self.expiry_time
is not used or checked against once set.self.expires_at
is never defined.if self.expired is False
: this will always report True
because expired
is never changed.
expires_at
is defined) will just return True