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