Improve DictMixin.
Replaced docstring with comments. Prevents subclass contamination. Added the missing __cmp__() method and a test for __cmp__(). Used try/except style in preference to has_key() followed by a look-up. Used iteritem() where possible to save creating a long key list and to save redundant lookups. Expanded .update() to look for the most helpful methods first and gradually work down to a mininum expected interface. Expanded documentation to be more clear on how to use the class.
This commit is contained in:
parent
782d940866
commit
8ddc176e2e
|
@ -43,19 +43,20 @@ class.
|
|||
|
||||
\begin{classdesc}{DictMixin}{}
|
||||
Mixin defining all dictionary methods for classes that already have
|
||||
a minimum dictionary interface including\method{__getitem__},
|
||||
\method{__setitem__}, \method{__delitem__}, and \method{keys}.
|
||||
a minimum dictionary interface including \method{__getitem__()},
|
||||
\method{__setitem__()}, \method{__delitem__()}, and \method{keys()}.
|
||||
|
||||
This mixin should be used as a superclass. Adding each of the
|
||||
above methods adds progressively more functionality. For instance,
|
||||
the absence of \method{__delitem__} precludes only \method{pop}
|
||||
and \method{popitem}.
|
||||
defining all but \method{__delitem__} will preclude only \method{pop}
|
||||
and \method{popitem} from the full interface.
|
||||
|
||||
While the four methods listed above are sufficient to support the
|
||||
entire dictionary interface, progessively more efficiency comes
|
||||
with defining \method{__contains__}, \method{__iter__}, and
|
||||
\method{iteritems}.
|
||||
In addition to the four base methods, progessively more efficiency
|
||||
comes with defining \method{__contains__()}, \method{__iter__()}, and
|
||||
\method{iteritems()}.
|
||||
|
||||
Since the mixin has no knowledge of the subclass constructor, it
|
||||
does not define \method{__init__()} or \method{copy()}.
|
||||
\end{classdesc}
|
||||
|
||||
|
||||
|
|
|
@ -62,13 +62,17 @@ class IterableUserDict(UserDict):
|
|||
return iter(self.data)
|
||||
|
||||
class DictMixin:
|
||||
'''Mixin defining all dictionary methods for classes that already have
|
||||
a minimum dictionary interface including getitem, setitem, delitem,
|
||||
and keys '''
|
||||
# Mixin defining all dictionary methods for classes that already have
|
||||
# a minimum dictionary interface including getitem, setitem, delitem,
|
||||
# and keys. Without knowledge of the subclass constructor, the mixin
|
||||
# does not define __init__() or copy(). In addition to the four base
|
||||
# methods, progessively more efficiency comes with defining
|
||||
# __contains__(), __iter__(), and iteritems().
|
||||
|
||||
# first level provided by subclass: getitem, setitem, delitem, and keys
|
||||
|
||||
# second level definitions which assume only getitem and keys
|
||||
# second level definitions support higher levels
|
||||
def __iter__(self):
|
||||
for k in self.keys():
|
||||
yield k
|
||||
def has_key(self, key):
|
||||
try:
|
||||
value = self[key]
|
||||
|
@ -76,34 +80,30 @@ class DictMixin:
|
|||
return False
|
||||
return True
|
||||
__contains__ = has_key
|
||||
def __iter__(self):
|
||||
for k in self.keys():
|
||||
yield k
|
||||
def __len__(self):
|
||||
return len(self.keys())
|
||||
|
||||
# third level uses second level instead of first
|
||||
# third level takes advantage of second level definitions
|
||||
def iteritems(self):
|
||||
for k in self:
|
||||
yield (k, self[k])
|
||||
iterkeys = __iter__
|
||||
|
||||
# fourth level uses second and third levels instead of first
|
||||
# fourth level uses definitions from lower levels
|
||||
def itervalues(self):
|
||||
for _, v in self.iteritems():
|
||||
yield v
|
||||
def values(self):
|
||||
return [self[key] for key in self.keys()]
|
||||
return [v for _, v in self.iteritems()]
|
||||
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:
|
||||
try:
|
||||
return self[key]
|
||||
except KeyError:
|
||||
self[key] = default
|
||||
return default
|
||||
return self[key]
|
||||
return default
|
||||
def pop(self, key):
|
||||
value = self[key]
|
||||
del self[key]
|
||||
|
@ -112,15 +112,30 @@ class DictMixin:
|
|||
try:
|
||||
k, v = self.iteritems().next()
|
||||
except StopIteration:
|
||||
raise KeyError, 'dictionary is empty'
|
||||
raise KeyError, 'container is empty'
|
||||
del self[k]
|
||||
return (k, v)
|
||||
def update(self, other):
|
||||
for key in other.keys():
|
||||
self[key] = other[key]
|
||||
# Make progressively weaker assumptions about "other"
|
||||
if hasattr(other, 'iteritems'): # iteritems saves memory and lookups
|
||||
for k, v in other.iteritems():
|
||||
self[k] = v
|
||||
elif hasattr(other, '__iter__'): # iter saves memory
|
||||
for k in other:
|
||||
self[k] = other[k]
|
||||
else:
|
||||
for k in other.keys():
|
||||
self[k] = other[k]
|
||||
def get(self, key, default=None):
|
||||
if key in self:
|
||||
try:
|
||||
return self[key]
|
||||
return default
|
||||
except KeyError:
|
||||
return default
|
||||
def __repr__(self):
|
||||
return repr(dict(self.items()))
|
||||
return repr(dict(self.iteritems()))
|
||||
def __cmp__(self, other):
|
||||
if isinstance(other, DictMixin):
|
||||
other = dict(other.iteritems())
|
||||
return cmp(dict(self.iteritems()), other)
|
||||
def __len__(self):
|
||||
return len(self.keys())
|
||||
|
|
|
@ -210,9 +210,8 @@ else:
|
|||
s.update({10: 'ten', 20:'twenty'}) # update
|
||||
verify(s[10]=='ten' and s[20]=='twenty')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
verify(s == {10: 'ten', 20:'twenty'}) # cmp
|
||||
t = SeqDict()
|
||||
t[20] = 'twenty'
|
||||
t[10] = 'ten'
|
||||
verify(s == t)
|
||||
|
|
Loading…
Reference in New Issue