1 # Copyright (c) 2009 Raymond Hettinger
3 # Permission is hereby granted, free of charge, to any person
4 # obtaining a copy of this software and associated documentation files
5 # (the "Software"), to deal in the Software without restriction,
6 # including without limitation the rights to use, copy, modify, merge,
7 # publish, distribute, sublicense, and/or sell copies of the Software,
8 # and to permit persons to whom the Software is furnished to do so,
9 # subject to the following conditions:
11 # The above copyright notice and this permission notice shall be
12 # included in all copies or substantial portions of the Software.
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 # OTHER DEALINGS IN THE SOFTWARE.
23 from UserDict
import DictMixin
25 class OrderedDict(dict, DictMixin
):
27 def __init__(self
, *args
, **kwds
):
29 raise TypeError('expected at most 1 arguments, got %d' % len(args
))
32 except AttributeError:
34 self
.update(*args
, **kwds
)
38 end
+= [None, end
, end
] # sentinel node for doubly linked list
39 self
.__map
= {} # key --> [key, prev, next]
42 def __setitem__(self
, key
, value
):
46 curr
[2] = end
[1] = self
.__map
[key
] = [key
, curr
, end
]
47 dict.__setitem
__(self
, key
, value
)
49 def __delitem__(self
, key
):
50 dict.__delitem
__(self
, key
)
51 key
, prev
, next
= self
.__map
.pop(key
)
58 while curr
is not end
:
62 def __reversed__(self
):
65 while curr
is not end
:
69 def popitem(self
, last
=True):
71 raise KeyError('dictionary is empty')
73 key
= reversed(self
).next()
75 key
= iter(self
).next()
80 items
= [[k
, self
[k
]] for k
in self
]
81 tmp
= self
.__map
, self
.__end
82 del self
.__map
, self
.__end
83 inst_dict
= vars(self
).copy()
84 self
.__map
, self
.__end
= tmp
86 return (self
.__class
__, (items
,), inst_dict
)
87 return self
.__class
__, (items
,)
92 setdefault
= DictMixin
.setdefault
93 update
= DictMixin
.update
95 values
= DictMixin
.values
96 items
= DictMixin
.items
97 iterkeys
= DictMixin
.iterkeys
98 itervalues
= DictMixin
.itervalues
99 iteritems
= DictMixin
.iteritems
103 return '%s()' % (self
.__class
__.__name
__,)
104 return '%s(%r)' % (self
.__class
__.__name
__, self
.items())
107 return self
.__class
__(self
)
110 def fromkeys(cls
, iterable
, value
=None):
116 def __eq__(self
, other
):
117 if isinstance(other
, OrderedDict
):
118 if len(self
) != len(other
):
120 for p
, q
in zip(self
.items(), other
.items()):
124 return dict.__eq
__(self
, other
)
126 def __ne__(self
, other
):
127 return not self
== other