|
1 """A more or less complete user-defined wrapper around dictionary objects.""" |
|
2 |
|
3 class UserDict: |
|
4 def __init__(self, dict=None, **kwargs): |
|
5 self.data = {} |
|
6 if dict is not None: |
|
7 self.update(dict) |
|
8 if len(kwargs): |
|
9 self.update(kwargs) |
|
10 def __repr__(self): return repr(self.data) |
|
11 def __cmp__(self, dict): |
|
12 if isinstance(dict, UserDict): |
|
13 return cmp(self.data, dict.data) |
|
14 else: |
|
15 return cmp(self.data, dict) |
|
16 def __len__(self): return len(self.data) |
|
17 def __getitem__(self, key): |
|
18 if key in self.data: |
|
19 return self.data[key] |
|
20 if hasattr(self.__class__, "__missing__"): |
|
21 return self.__class__.__missing__(self, key) |
|
22 raise KeyError(key) |
|
23 def __setitem__(self, key, item): self.data[key] = item |
|
24 def __delitem__(self, key): del self.data[key] |
|
25 def clear(self): self.data.clear() |
|
26 def copy(self): |
|
27 if self.__class__ is UserDict: |
|
28 return UserDict(self.data.copy()) |
|
29 import copy |
|
30 data = self.data |
|
31 try: |
|
32 self.data = {} |
|
33 c = copy.copy(self) |
|
34 finally: |
|
35 self.data = data |
|
36 c.update(self) |
|
37 return c |
|
38 def keys(self): return self.data.keys() |
|
39 def items(self): return self.data.items() |
|
40 def iteritems(self): return self.data.iteritems() |
|
41 def iterkeys(self): return self.data.iterkeys() |
|
42 def itervalues(self): return self.data.itervalues() |
|
43 def values(self): return self.data.values() |
|
44 def has_key(self, key): return key in self.data |
|
45 def update(self, dict=None, **kwargs): |
|
46 if dict is None: |
|
47 pass |
|
48 elif isinstance(dict, UserDict): |
|
49 self.data.update(dict.data) |
|
50 elif isinstance(dict, type({})) or not hasattr(dict, 'items'): |
|
51 self.data.update(dict) |
|
52 else: |
|
53 for k, v in dict.items(): |
|
54 self[k] = v |
|
55 if len(kwargs): |
|
56 self.data.update(kwargs) |
|
57 def get(self, key, failobj=None): |
|
58 if key not in self: |
|
59 return failobj |
|
60 return self[key] |
|
61 def setdefault(self, key, failobj=None): |
|
62 if key not in self: |
|
63 self[key] = failobj |
|
64 return self[key] |
|
65 def pop(self, key, *args): |
|
66 return self.data.pop(key, *args) |
|
67 def popitem(self): |
|
68 return self.data.popitem() |
|
69 def __contains__(self, key): |
|
70 return key in self.data |
|
71 @classmethod |
|
72 def fromkeys(cls, iterable, value=None): |
|
73 d = cls() |
|
74 for key in iterable: |
|
75 d[key] = value |
|
76 return d |
|
77 |
|
78 class IterableUserDict(UserDict): |
|
79 def __iter__(self): |
|
80 return iter(self.data) |
|
81 |
|
82 import _abcoll |
|
83 _abcoll.MutableMapping.register(IterableUserDict) |
|
84 |
|
85 |
|
86 class DictMixin: |
|
87 # Mixin defining all dictionary methods for classes that already have |
|
88 # a minimum dictionary interface including getitem, setitem, delitem, |
|
89 # and keys. Without knowledge of the subclass constructor, the mixin |
|
90 # does not define __init__() or copy(). In addition to the four base |
|
91 # methods, progressively more efficiency comes with defining |
|
92 # __contains__(), __iter__(), and iteritems(). |
|
93 |
|
94 # second level definitions support higher levels |
|
95 def __iter__(self): |
|
96 for k in self.keys(): |
|
97 yield k |
|
98 def has_key(self, key): |
|
99 try: |
|
100 value = self[key] |
|
101 except KeyError: |
|
102 return False |
|
103 return True |
|
104 def __contains__(self, key): |
|
105 return self.has_key(key) |
|
106 |
|
107 # third level takes advantage of second level definitions |
|
108 def iteritems(self): |
|
109 for k in self: |
|
110 yield (k, self[k]) |
|
111 def iterkeys(self): |
|
112 return self.__iter__() |
|
113 |
|
114 # fourth level uses definitions from lower levels |
|
115 def itervalues(self): |
|
116 for _, v in self.iteritems(): |
|
117 yield v |
|
118 def values(self): |
|
119 return [v for _, v in self.iteritems()] |
|
120 def items(self): |
|
121 return list(self.iteritems()) |
|
122 def clear(self): |
|
123 for key in self.keys(): |
|
124 del self[key] |
|
125 def setdefault(self, key, default=None): |
|
126 try: |
|
127 return self[key] |
|
128 except KeyError: |
|
129 self[key] = default |
|
130 return default |
|
131 def pop(self, key, *args): |
|
132 if len(args) > 1: |
|
133 raise TypeError, "pop expected at most 2 arguments, got "\ |
|
134 + repr(1 + len(args)) |
|
135 try: |
|
136 value = self[key] |
|
137 except KeyError: |
|
138 if args: |
|
139 return args[0] |
|
140 raise |
|
141 del self[key] |
|
142 return value |
|
143 def popitem(self): |
|
144 try: |
|
145 k, v = self.iteritems().next() |
|
146 except StopIteration: |
|
147 raise KeyError, 'container is empty' |
|
148 del self[k] |
|
149 return (k, v) |
|
150 def update(self, other=None, **kwargs): |
|
151 # Make progressively weaker assumptions about "other" |
|
152 if other is None: |
|
153 pass |
|
154 elif hasattr(other, 'iteritems'): # iteritems saves memory and lookups |
|
155 for k, v in other.iteritems(): |
|
156 self[k] = v |
|
157 elif hasattr(other, 'keys'): |
|
158 for k in other.keys(): |
|
159 self[k] = other[k] |
|
160 else: |
|
161 for k, v in other: |
|
162 self[k] = v |
|
163 if kwargs: |
|
164 self.update(kwargs) |
|
165 def get(self, key, default=None): |
|
166 try: |
|
167 return self[key] |
|
168 except KeyError: |
|
169 return default |
|
170 def __repr__(self): |
|
171 return repr(dict(self.iteritems())) |
|
172 def __cmp__(self, other): |
|
173 if other is None: |
|
174 return 1 |
|
175 if isinstance(other, DictMixin): |
|
176 other = dict(other.iteritems()) |
|
177 return cmp(dict(self.iteritems()), other) |
|
178 def __len__(self): |
|
179 return len(self.keys()) |