|
1 | | -# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. |
2 | | -# Passes Python2.7's test suite and incorporates all the latest updates. |
3 | | -# taken from: http://code.activestate.com/recipes/576693/ |
4 | | - |
5 | | -try: |
6 | | - # This will fail in versions that don't have OrderedDict |
7 | | - from collections import OrderedDict |
8 | | - |
9 | | -except ImportError: |
10 | | - try: |
11 | | - from thread import get_ident as _get_ident |
12 | | - except ImportError: |
13 | | - from dummy_thread import get_ident as _get_ident |
14 | | - |
15 | | - try: |
16 | | - from _abcoll import KeysView, ValuesView, ItemsView |
17 | | - except ImportError: |
18 | | - pass |
19 | | - |
20 | | - |
21 | | - class OrderedDict(dict): |
22 | | - 'Dictionary that remembers insertion order' |
23 | | - # An inherited dict maps keys to values. |
24 | | - # The inherited dict provides __getitem__, __len__, __contains__, and get. |
25 | | - # The remaining methods are order-aware. |
26 | | - # Big-O running times for all methods are the same as for regular dictionaries. |
27 | | - |
28 | | - # The internal self.__map dictionary maps keys to links in a doubly linked list. |
29 | | - # The circular doubly linked list starts and ends with a sentinel element. |
30 | | - # The sentinel element never gets deleted (this simplifies the algorithm). |
31 | | - # Each link is stored as a list of length three: [PREV, NEXT, KEY]. |
32 | | - |
33 | | - def __init__(self, *args, **kwds): |
34 | | - '''Initialize an ordered dictionary. Signature is the same as for |
35 | | - regular dictionaries, but keyword arguments are not recommended |
36 | | - because their insertion order is arbitrary. |
37 | | -
|
38 | | - ''' |
39 | | - if len(args) > 1: |
40 | | - raise TypeError('expected at most 1 arguments, got %d' % len(args)) |
41 | | - try: |
42 | | - self.__root |
43 | | - except AttributeError: |
44 | | - self.__root = root = [] # sentinel node |
45 | | - root[:] = [root, root, None] |
46 | | - self.__map = {} |
47 | | - self.__update(*args, **kwds) |
48 | | - |
49 | | - def __setitem__(self, key, value, dict_setitem=dict.__setitem__): |
50 | | - 'od.__setitem__(i, y) <==> od[i]=y' |
51 | | - # Setting a new item creates a new link which goes at the end of the linked |
52 | | - # list, and the inherited dictionary is updated with the new key/value pair. |
53 | | - if key not in self: |
54 | | - root = self.__root |
55 | | - last = root[0] |
56 | | - last[1] = root[0] = self.__map[key] = [last, root, key] |
57 | | - dict_setitem(self, key, value) |
58 | | - |
59 | | - def __delitem__(self, key, dict_delitem=dict.__delitem__): |
60 | | - 'od.__delitem__(y) <==> del od[y]' |
61 | | - # Deleting an existing item uses self.__map to find the link which is |
62 | | - # then removed by updating the links in the predecessor and successor nodes. |
63 | | - dict_delitem(self, key) |
64 | | - link_prev, link_next, key = self.__map.pop(key) |
65 | | - link_prev[1] = link_next |
66 | | - link_next[0] = link_prev |
67 | | - |
68 | | - def __iter__(self): |
69 | | - 'od.__iter__() <==> iter(od)' |
70 | | - root = self.__root |
71 | | - curr = root[1] |
72 | | - while curr is not root: |
73 | | - yield curr[2] |
74 | | - curr = curr[1] |
75 | | - |
76 | | - def __reversed__(self): |
77 | | - 'od.__reversed__() <==> reversed(od)' |
78 | | - root = self.__root |
79 | | - curr = root[0] |
80 | | - while curr is not root: |
81 | | - yield curr[2] |
82 | | - curr = curr[0] |
83 | | - |
84 | | - def clear(self): |
85 | | - 'od.clear() -> None. Remove all items from od.' |
86 | | - try: |
87 | | - for node in self.__map.itervalues(): |
88 | | - del node[:] |
89 | | - root = self.__root |
90 | | - root[:] = [root, root, None] |
91 | | - self.__map.clear() |
92 | | - except AttributeError: |
93 | | - pass |
94 | | - dict.clear(self) |
95 | | - |
96 | | - def popitem(self, last=True): |
97 | | - '''od.popitem() -> (k, v), return and remove a (key, value) pair. |
98 | | - Pairs are returned in LIFO order if last is true or FIFO order if false. |
99 | | -
|
100 | | - ''' |
101 | | - if not self: |
102 | | - raise KeyError('dictionary is empty') |
103 | | - root = self.__root |
104 | | - if last: |
105 | | - link = root[0] |
106 | | - link_prev = link[0] |
107 | | - link_prev[1] = root |
108 | | - root[0] = link_prev |
109 | | - else: |
110 | | - link = root[1] |
111 | | - link_next = link[1] |
112 | | - root[1] = link_next |
113 | | - link_next[0] = root |
114 | | - key = link[2] |
115 | | - del self.__map[key] |
116 | | - value = dict.pop(self, key) |
117 | | - return key, value |
118 | | - |
119 | | - # -- the following methods do not depend on the internal structure -- |
120 | | - |
121 | | - def keys(self): |
122 | | - 'od.keys() -> list of keys in od' |
123 | | - return list(self) |
124 | | - |
125 | | - def values(self): |
126 | | - 'od.values() -> list of values in od' |
127 | | - return [self[key] for key in self] |
128 | | - |
129 | | - def items(self): |
130 | | - 'od.items() -> list of (key, value) pairs in od' |
131 | | - return [(key, self[key]) for key in self] |
132 | | - |
133 | | - def iterkeys(self): |
134 | | - 'od.iterkeys() -> an iterator over the keys in od' |
135 | | - return iter(self) |
136 | | - |
137 | | - def itervalues(self): |
138 | | - 'od.itervalues -> an iterator over the values in od' |
139 | | - for k in self: |
140 | | - yield self[k] |
141 | | - |
142 | | - def iteritems(self): |
143 | | - 'od.iteritems -> an iterator over the (key, value) items in od' |
144 | | - for k in self: |
145 | | - yield (k, self[k]) |
146 | | - |
147 | | - def update(*args, **kwds): |
148 | | - '''od.update(E, **F) -> None. Update od from dict/iterable E and F. |
149 | | -
|
150 | | - If E is a dict instance, does: for k in E: od[k] = E[k] |
151 | | - If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] |
152 | | - Or if E is an iterable of items, does: for k, v in E: od[k] = v |
153 | | - In either case, this is followed by: for k, v in F.items(): od[k] = v |
154 | | -
|
155 | | - ''' |
156 | | - if len(args) > 2: |
157 | | - raise TypeError('update() takes at most 2 positional ' |
158 | | - 'arguments (%d given)' % (len(args),)) |
159 | | - elif not args: |
160 | | - raise TypeError('update() takes at least 1 argument (0 given)') |
161 | | - self = args[0] |
162 | | - # Make progressively weaker assumptions about "other" |
163 | | - other = () |
164 | | - if len(args) == 2: |
165 | | - other = args[1] |
166 | | - if isinstance(other, dict): |
167 | | - for key in other: |
168 | | - self[key] = other[key] |
169 | | - elif hasattr(other, 'keys'): |
170 | | - for key in other.keys(): |
171 | | - self[key] = other[key] |
172 | | - else: |
173 | | - for key, value in other: |
174 | | - self[key] = value |
175 | | - for key, value in kwds.items(): |
176 | | - self[key] = value |
177 | | - |
178 | | - __update = update # let subclasses override update without breaking __init__ |
179 | | - |
180 | | - __marker = object() |
181 | | - |
182 | | - def pop(self, key, default=__marker): |
183 | | - '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. |
184 | | - If key is not found, d is returned if given, otherwise KeyError is raised. |
185 | | -
|
186 | | - ''' |
187 | | - if key in self: |
188 | | - result = self[key] |
189 | | - del self[key] |
190 | | - return result |
191 | | - if default is self.__marker: |
192 | | - raise KeyError(key) |
193 | | - return default |
194 | | - |
195 | | - def setdefault(self, key, default=None): |
196 | | - 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' |
197 | | - if key in self: |
198 | | - return self[key] |
199 | | - self[key] = default |
200 | | - return default |
201 | | - |
202 | | - def __repr__(self, _repr_running={}): |
203 | | - 'od.__repr__() <==> repr(od)' |
204 | | - call_key = id(self), _get_ident() |
205 | | - if call_key in _repr_running: |
206 | | - return '...' |
207 | | - _repr_running[call_key] = 1 |
208 | | - try: |
209 | | - if not self: |
210 | | - return '%s()' % (self.__class__.__name__,) |
211 | | - return '%s(%r)' % (self.__class__.__name__, self.items()) |
212 | | - finally: |
213 | | - del _repr_running[call_key] |
214 | | - |
215 | | - def __reduce__(self): |
216 | | - 'Return state information for pickling' |
217 | | - items = [[k, self[k]] for k in self] |
218 | | - inst_dict = vars(self).copy() |
219 | | - for k in vars(OrderedDict()): |
220 | | - inst_dict.pop(k, None) |
221 | | - if inst_dict: |
222 | | - return (self.__class__, (items,), inst_dict) |
223 | | - return self.__class__, (items,) |
224 | | - |
225 | | - def copy(self): |
226 | | - 'od.copy() -> a shallow copy of od' |
227 | | - return self.__class__(self) |
228 | | - |
229 | | - @classmethod |
230 | | - def fromkeys(cls, iterable, value=None): |
231 | | - '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S |
232 | | - and values equal to v (which defaults to None). |
233 | | -
|
234 | | - ''' |
235 | | - d = cls() |
236 | | - for key in iterable: |
237 | | - d[key] = value |
238 | | - return d |
239 | | - |
240 | | - def __eq__(self, other): |
241 | | - '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive |
242 | | - while comparison to a regular mapping is order-insensitive. |
243 | | -
|
244 | | - ''' |
245 | | - if isinstance(other, OrderedDict): |
246 | | - return len(self)==len(other) and self.items() == other.items() |
247 | | - return dict.__eq__(self, other) |
248 | | - |
249 | | - def __ne__(self, other): |
250 | | - return not self == other |
251 | | - |
252 | | - # -- the following methods are only used in Python 2.7 -- |
253 | | - |
254 | | - def viewkeys(self): |
255 | | - "od.viewkeys() -> a set-like object providing a view on od's keys" |
256 | | - return KeysView(self) |
257 | | - |
258 | | - def viewvalues(self): |
259 | | - "od.viewvalues() -> an object providing a view on od's values" |
260 | | - return ValuesView(self) |
261 | | - |
262 | | - def viewitems(self): |
263 | | - "od.viewitems() -> a set-like object providing a view on od's items" |
264 | | - return ItemsView(self) |
0 commit comments