From 9ba7daa9c706a76cc3eaf80661540457f0d80c56 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Wed, 12 Aug 2015 23:30:26 +0100 Subject: [PATCH] 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). --- attic/lrucache.py | 38 ++++++++++++++++++------------------- attic/testsuite/lrucache.py | 10 +--------- 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/attic/lrucache.py b/attic/lrucache.py index d4ea8a490..e02e1a6d0 100644 --- a/attic/lrucache.py +++ b/attic/lrucache.py @@ -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) diff --git a/attic/testsuite/lrucache.py b/attic/testsuite/lrucache.py index 60ceb41c3..b0dd2856f 100644 --- a/attic/testsuite/lrucache.py +++ b/attic/testsuite/lrucache.py @@ -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