class DictMixin:
'''Mixin defining all dictionary methods for classes that already have
a minimum dictionary interface including getitem, setitem, delitem,
and keys '''
# first level definitions should be implemented by the sub-class
def __getitem__(self, key):
raise NotImplementedError
def __setitem__(self, key, value):
raise NotImplementedError
def __delitem__(self, key):
raise NotImplementedError
def keys(self):
raise NotImplementedError
# second level definitions which assume only getitem and keys
def has_key(self, key):
return key in self.keys()
def __iter__(self):
for k in self.keys():
yield k
# third level uses second level instead of first
def __contains__(self, key):
return self.has_key(key)
def iteritems(self):
for k in self:
yield (k, self[k])
# fourth level uses second and third levels instead of first
def iterkeys(self):
return self.__iter__()
def itervalues(self):
for _, v in self.iteritems():
yield v
def values(self):
return list(self.itervalues())
def items(self):
return list(self.iteritems())
def clear(self):
for key in self.keys():
del self[key]
def setdefault(self, key, default):
if key not in self:
self[key] = default
return default
return self[key]
def popitem(self):
key = self.keys()[0]
value = self[key]
del self[key]
return (key, value)
def update(self, other):
for key in other.keys():
self[key] = other[key]
def get(self, key, default):
if key in self:
return self[key]
return default
def __repr__(self):
return repr(dict(self.items()))
def MakeFullDict(tgt):
'Extends the dictionary interface for existing classes'
tgt.__bases__ = tuple(list(tgt.__bases__) + [DictMixin])
### Example of extending shelve.py to have a full dictionary interface
import shelve
MakeFullDict(shelve.Shelf)
s = shelve.open('a.shl')
s['name'] = 'john'
s['world'] = 'earth'
print s.has_key('name')
print s.__contains__('name')
print 'name' in s
for k in s: print k
for k,v in s.iteritems(): print k,v
for k in s.iterkeys(): print k
for v in s.itervalues(): print v
print s.values()
print s.setdefault( 'addr', 1 )
print s.setdefault( 'addr', 2 )
del s['addr']
print s.popitem()
s.update( {'age':38} )
print s.keys()
print s.get('age',17)
print s.get('salary', 2000)
print s
print `s`
### Example of a binary tree expanding to a full dictionary iterface
class TreeDict(object, DictMixin):
__slots__ = [left, right, key, value]
def __init__(self, key, value):
self.left, self.right, self.key, self.value = None, None, key, value
def __getitem__(self, key):
if key == self.key: return value
next = self.left
if key > self.key: next=self.right
if next is None: raise KeyError, key
return next[key]
def __setitem__(self, key, value):
if key == self.key:
self.value = value
return
if key < self.key:
if self.left is None:
self.left = TreeDict(key,value)
else:
self.left[key]=value
else:
if self.right is None:
self.right = TreeDict(key,value)
else:
self.right[key]=value
def keys(self):
ans = [self.key]
if self.left is not None: ans.extend(self.left.keys())
if self.right is not None: ans.extend(self.right.keys())
return ans
def items(self):
'DictMixin does this; but it can be done faster by the base class'
ans = [(self.key, self.value)]
if self.left is not None: ans.extend(self.left.items())
if self.right is not None: ans.extend(self.right.items())
return ans
def iteritems(self):
'DictMixin does this; but it can be done faster by the base class'
for item in self.items():
yield item