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:
Raymond Hettinger 2002-11-18 04:34:10 +00:00
parent 782d940866
commit 8ddc176e2e
3 changed files with 52 additions and 37 deletions

View File

@ -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}

View File

@ -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())

View File

@ -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)