Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8ddc176

Browse files
committed
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.
1 parent 782d940 commit 8ddc176

3 files changed

Lines changed: 52 additions & 37 deletions

File tree

Doc/lib/libuserdict.tex

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,20 @@ \section{\module{UserDict} ---
4343

4444
\begin{classdesc}{DictMixin}{}
4545
Mixin defining all dictionary methods for classes that already have
46-
a minimum dictionary interface including\method{__getitem__},
47-
\method{__setitem__}, \method{__delitem__}, and \method{keys}.
46+
a minimum dictionary interface including \method{__getitem__()},
47+
\method{__setitem__()}, \method{__delitem__()}, and \method{keys()}.
4848

4949
This mixin should be used as a superclass. Adding each of the
5050
above methods adds progressively more functionality. For instance,
51-
the absence of \method{__delitem__} precludes only \method{pop}
52-
and \method{popitem}.
51+
defining all but \method{__delitem__} will preclude only \method{pop}
52+
and \method{popitem} from the full interface.
5353

54-
While the four methods listed above are sufficient to support the
55-
entire dictionary interface, progessively more efficiency comes
56-
with defining \method{__contains__}, \method{__iter__}, and
57-
\method{iteritems}.
54+
In addition to the four base methods, progessively more efficiency
55+
comes with defining \method{__contains__()}, \method{__iter__()}, and
56+
\method{iteritems()}.
5857

58+
Since the mixin has no knowledge of the subclass constructor, it
59+
does not define \method{__init__()} or \method{copy()}.
5960
\end{classdesc}
6061

6162

Lib/UserDict.py

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -62,48 +62,48 @@ def __iter__(self):
6262
return iter(self.data)
6363

6464
class DictMixin:
65-
'''Mixin defining all dictionary methods for classes that already have
66-
a minimum dictionary interface including getitem, setitem, delitem,
67-
and keys '''
65+
# Mixin defining all dictionary methods for classes that already have
66+
# a minimum dictionary interface including getitem, setitem, delitem,
67+
# and keys. Without knowledge of the subclass constructor, the mixin
68+
# does not define __init__() or copy(). In addition to the four base
69+
# methods, progessively more efficiency comes with defining
70+
# __contains__(), __iter__(), and iteritems().
6871

69-
# first level provided by subclass: getitem, setitem, delitem, and keys
70-
71-
# second level definitions which assume only getitem and keys
72+
# second level definitions support higher levels
73+
def __iter__(self):
74+
for k in self.keys():
75+
yield k
7276
def has_key(self, key):
7377
try:
7478
value = self[key]
7579
except KeyError:
7680
return False
7781
return True
7882
__contains__ = has_key
79-
def __iter__(self):
80-
for k in self.keys():
81-
yield k
82-
def __len__(self):
83-
return len(self.keys())
8483

85-
# third level uses second level instead of first
84+
# third level takes advantage of second level definitions
8685
def iteritems(self):
8786
for k in self:
8887
yield (k, self[k])
8988
iterkeys = __iter__
9089

91-
# fourth level uses second and third levels instead of first
90+
# fourth level uses definitions from lower levels
9291
def itervalues(self):
9392
for _, v in self.iteritems():
9493
yield v
9594
def values(self):
96-
return [self[key] for key in self.keys()]
95+
return [v for _, v in self.iteritems()]
9796
def items(self):
9897
return list(self.iteritems())
9998
def clear(self):
10099
for key in self.keys():
101100
del self[key]
102101
def setdefault(self, key, default):
103-
if key not in self:
102+
try:
103+
return self[key]
104+
except KeyError:
104105
self[key] = default
105-
return default
106-
return self[key]
106+
return default
107107
def pop(self, key):
108108
value = self[key]
109109
del self[key]
@@ -112,15 +112,30 @@ def popitem(self):
112112
try:
113113
k, v = self.iteritems().next()
114114
except StopIteration:
115-
raise KeyError, 'dictionary is empty'
115+
raise KeyError, 'container is empty'
116116
del self[k]
117117
return (k, v)
118118
def update(self, other):
119-
for key in other.keys():
120-
self[key] = other[key]
119+
# Make progressively weaker assumptions about "other"
120+
if hasattr(other, 'iteritems'): # iteritems saves memory and lookups
121+
for k, v in other.iteritems():
122+
self[k] = v
123+
elif hasattr(other, '__iter__'): # iter saves memory
124+
for k in other:
125+
self[k] = other[k]
126+
else:
127+
for k in other.keys():
128+
self[k] = other[k]
121129
def get(self, key, default=None):
122-
if key in self:
130+
try:
123131
return self[key]
124-
return default
132+
except KeyError:
133+
return default
125134
def __repr__(self):
126-
return repr(dict(self.items()))
135+
return repr(dict(self.iteritems()))
136+
def __cmp__(self, other):
137+
if isinstance(other, DictMixin):
138+
other = dict(other.iteritems())
139+
return cmp(dict(self.iteritems()), other)
140+
def __len__(self):
141+
return len(self.keys())

Lib/test/test_userdict.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,8 @@ def keys(self):
210210
s.update({10: 'ten', 20:'twenty'}) # update
211211
verify(s[10]=='ten' and s[20]=='twenty')
212212

213-
214-
215-
216-
217-
218-
213+
verify(s == {10: 'ten', 20:'twenty'}) # cmp
214+
t = SeqDict()
215+
t[20] = 'twenty'
216+
t[10] = 'ten'
217+
verify(s == t)

0 commit comments

Comments
 (0)