Sono d'accordo con Doc Brown sulla questione della sostituzione di Liskov, ma se non si eredita da Ditt, come saprai che stai supportando la giusta interfaccia astratta? Posso suggerire di usare MutableMapping
dal modulo delle collezioni?
La docstring per MutableMapping
della sorgente ha il seguente aspetto:
"""A MutableMapping is a generic container for associating
key/value pairs.
This class provides concrete generic implementations of all
methods except for __getitem__, __setitem__, __delitem__,
__iter__, and __len__.
"""
Ciò significa che quei metodi magici sono tutto ciò che devi implementare per ottenere la stessa funzionalità dict. Potrebbe sembrare qualcosa del genere (testato nominalmente in Python 2 e 3):
import collections
class LimitedDict(collections.MutableMapping):
def __init__(self, maxlen=10):
self.maxlen = maxlen
self.latest = collections.deque(maxlen=maxlen)
self.data = {}
def __setitem__(self, key, value):
'''ld[i] = y'''
item_in = key in self.data
if len(self.latest) >= self.maxlen and not item_in:
self.latest.pop()
elif item_in:
self.latest.remove(key)
self.latest.appendleft(key)
self.data[key] = value
def __delitem__(self, key):
'''del ld[i]'''
del self.data[key]
self.latest.remove(key)
def __getitem__(self, key):
return self.data[key]
def __iter__(self):
for key in self.latest:
yield key
def __len__(self):
return len(self.latest)
E non ha testato molto, ma l'ho fatto e si comporta come previsto:
def main():
ld = LimitedDict(3)
ld['foo'] = 1
print(ld['foo'])
ld['bar'] = 2
print(ld['bar'])
del ld['bar']
assert 'bar' not in ld
ld['bar'] = 3
ld['foo'] = 4
ld['baz'] = 5
ld['quux'] = 6
assert 'bar' not in ld
for key, value in ld.items():
print(key, value)
ld.update(foo=7, bar=8, baz=9)
try:
del ld['quux']
except KeyError:
raised = True
assert raised
assert not isinstance(ld, dict)
Funziona sia in Python 2.6 e 3.3, e puoi usare ad es. iteritems
anche in 2.
Inoltre, setdefault
è disponibile, quindi non hai davvero bisogno di defaultdict
, neanche. Ecco l'aiuto su come funziona:
>>> help(dict.setdefault)
Help on method_descriptor:
setdefault(...)
D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D