An LRU cache is simply a mapping that preserves insertion order so the most recently used item can be moved to the front and the least recently used item can be removed when the maximum size of the cache is reached. In both Python 2 and Python 3, such a data structure can be found in the standard library as collections.OrderedDict
with the popitem(last=False)
method.
To more easily initialize an LRU cache for each column name, you can also use collections.defaultdict
:
from collections import defaultdict, OrderedDict
class Client:
def __init__(self, cache_size=3): # a cache size of only 3 for demo purposes
self.col_cache = defaultdict(OrderedDict)
self.cache_size = cache_size
def get_col(self, col_name, time):
cache = self.col_cache[col_name]
try:
cache[time] = cache.pop(time)
except KeyError:
if len(cache) >= self.cache_size:
cache.popitem(last=False)
cache[time] = '%s at %s' % (col_name, time) # make DB query here
print(cache)
return cache[time]
so that:
c = Client()
print(c.get_col('foo', 1))
print(c.get_col('foo', 2))
print(c.get_col('foo', 3))
print(c.get_col('foo', 4))
print(c.get_col('foo', 3))
print(c.get_col('foo', 1))
outputs:
OrderedDict([(1, 'foo at 1')])
foo at 1
OrderedDict([(1, 'foo at 1'), (2, 'foo at 2')])
foo at 2
OrderedDict([(1, 'foo at 1'), (2, 'foo at 2'), (3, 'foo at 3')])
foo at 3
OrderedDict([(2, 'foo at 2'), (3, 'foo at 3'), (4, 'foo at 4')])
foo at 4
OrderedDict([(2, 'foo at 2'), (4, 'foo at 4'), (3, 'foo at 3')])
foo at 3
OrderedDict([(4, 'foo at 4'), (3, 'foo at 3'), (1, 'foo at 1')])
foo at 1
Demo: Try it online!
Note that since Python 3.2, collections.OrderedDict
also has a move_to_end
method for you to move an item to the front, so you can change the line:
cache[time] = cache.pop(time)
to simply:
cache.move_to_end(time)
@lru_cache
you are using in Python 2 a backport using some external library? – Quickelfunctools
. the one in functools if for py3+ iirc – Perrine