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