mirror of
https://github.com/borgbackup/borg.git
synced 2025-02-23 14:41:43 +00:00
lrucache - simpler _not_ to inherit from dict
We need to make sure dispose() is always called when necessary. Using inheritance it's just too easy to forget a method, that we needed to override. I also find it confusing when an override method calls another method, and you have yet to see whether the latter method is overridden or not. It didn't help that most of these methods are actually operator overloads. This turns out to require _less_ code :-). (Admittedly the code could have been reduced a bit anyway because python3's super() can be called without any arguments).
This commit is contained in:
parent
e3f671c4fb
commit
9ba7daa9c7
2 changed files with 19 additions and 29 deletions
|
@ -1,20 +1,19 @@
|
|||
class LRUCache(dict):
|
||||
|
||||
class LRUCache:
|
||||
def __init__(self, capacity, dispose):
|
||||
super(LRUCache, self).__init__()
|
||||
self._cache = {}
|
||||
self._lru = []
|
||||
self._capacity = capacity
|
||||
self._dispose = dispose
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
assert key not in self, (
|
||||
assert key not in self._cache, (
|
||||
"Unexpected attempt to replace a cached item."
|
||||
" If this is intended, please delete or pop the old item first."
|
||||
" The dispose function will be called on delete (but not pop).")
|
||||
" If this is intended, please delete the old item first."
|
||||
" The dispose function will be called on delete.")
|
||||
self._lru.append(key)
|
||||
while len(self._lru) > self._capacity:
|
||||
del self[self._lru[0]]
|
||||
return super(LRUCache, self).__setitem__(key, value)
|
||||
self._cache[key] = value
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
|
@ -22,7 +21,7 @@ def __getitem__(self, key):
|
|||
self._lru.append(key)
|
||||
except ValueError:
|
||||
pass
|
||||
return super(LRUCache, self).__getitem__(key)
|
||||
return self._cache[key]
|
||||
|
||||
def __delitem__(self, key):
|
||||
try:
|
||||
|
@ -30,23 +29,22 @@ def __delitem__(self, key):
|
|||
except ValueError:
|
||||
pass
|
||||
error = KeyError(key)
|
||||
removed = super(LRUCache, self).pop(key, error)
|
||||
removed = self._cache.pop(key, error)
|
||||
if removed == error:
|
||||
raise error
|
||||
self._dispose(removed)
|
||||
|
||||
def pop(self, key, default=None):
|
||||
try:
|
||||
self._lru.remove(key)
|
||||
except ValueError:
|
||||
pass
|
||||
return super(LRUCache, self).pop(key, default)
|
||||
def __contains__(self, key):
|
||||
return key in self._cache
|
||||
|
||||
def clear(self):
|
||||
for value in self.values():
|
||||
for value in self._cache.values():
|
||||
self._dispose(value)
|
||||
super(LRUCache, self).clear()
|
||||
self._cache.clear()
|
||||
|
||||
def _not_implemented(self, *args, **kw):
|
||||
raise NotImplementedError
|
||||
popitem = setdefault = update = _not_implemented
|
||||
# useful for testing
|
||||
def items(self):
|
||||
return self._cache.items()
|
||||
|
||||
def __len__(self):
|
||||
return len(self._cache)
|
||||
|
|
|
@ -10,8 +10,7 @@ def test(self):
|
|||
for i, x in enumerate('abc'):
|
||||
c[x] = i
|
||||
self.assert_equal(len(c), 2)
|
||||
self.assert_equal(set(c), set(['b', 'c']))
|
||||
self.assert_equal(set(c.items()), set([('b', 1), ('c', 2)]))
|
||||
self.assert_equal(c.items(), set([('b', 1), ('c', 2)]))
|
||||
self.assert_equal(False, 'a' in c)
|
||||
self.assert_equal(True, 'b' in c)
|
||||
self.assert_raises(KeyError, lambda: c['a'])
|
||||
|
@ -25,10 +24,3 @@ def test(self):
|
|||
self.assert_equal(len(c), 1)
|
||||
self.assert_raises(KeyError, lambda: c['c'])
|
||||
self.assert_equal(c['d'], 3)
|
||||
|
||||
def test_pop(self):
|
||||
c = LRUCache(2, dispose=lambda _: None)
|
||||
c[1] = 1
|
||||
c[2] = 2
|
||||
c.pop(1)
|
||||
c[3] = 3
|
||||
|
|
Loading…
Reference in a new issue