summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2002-11-18 04:34:10 (GMT)
committerRaymond Hettinger <python@rcn.com>2002-11-18 04:34:10 (GMT)
commit8ddc176e2e7ef11b2c46062b29563bc776f177b8 (patch)
tree9420f4a710a3ae47f72c846c0b6f5e0c1a9a29bd
parent782d9408667f8df924d865088839633f53cf89bc (diff)
downloadcpython-8ddc176e2e7ef11b2c46062b29563bc776f177b8.zip
cpython-8ddc176e2e7ef11b2c46062b29563bc776f177b8.tar.gz
cpython-8ddc176e2e7ef11b2c46062b29563bc776f177b8.tar.bz2
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.
-rw-r--r--Doc/lib/libuserdict.tex17
-rw-r--r--Lib/UserDict.py61
-rw-r--r--Lib/test/test_userdict.py11
3 files changed, 52 insertions, 37 deletions
diff --git a/Doc/lib/libuserdict.tex b/Doc/lib/libuserdict.tex
index e01c546..ef5c1bf 100644
--- a/Doc/lib/libuserdict.tex
+++ b/Doc/lib/libuserdict.tex
@@ -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}
diff --git a/Lib/UserDict.py b/Lib/UserDict.py
index b6b36b2..96f049d 100644
--- a/Lib/UserDict.py
+++ b/Lib/UserDict.py
@@ -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())
diff --git a/Lib/test/test_userdict.py b/Lib/test/test_userdict.py
index 6f3b853..a59419d 100644
--- a/Lib/test/test_userdict.py
+++ b/Lib/test/test_userdict.py
@@ -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)