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