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