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
26 class OrderedDict(dict, DictMixin
):
28 def __init__(self
, *args
, **kwds
):
30 raise TypeError('expected at most 1 arguments, got %d' % len(args
))
33 except AttributeError:
35 self
.update(*args
, **kwds
)
39 end
+= [None, end
, end
] # sentinel node for doubly linked list
40 self
.__map
= {} # key --> [key, prev, next]
43 def __setitem__(self
, key
, value
):
47 curr
[2] = end
[1] = self
.__map
[key
] = [key
, curr
, end
]
48 dict.__setitem
__(self
, key
, value
)
50 def __delitem__(self
, key
):
51 dict.__delitem
__(self
, key
)
52 key
, prev
, next
= self
.__map
.pop(key
)
59 while curr
is not end
:
63 def __reversed__(self
):
66 while curr
is not end
:
70 def popitem(self
, last
=True):
72 raise KeyError('dictionary is empty')
74 key
= reversed(self
).next()
76 key
= iter(self
).next()
81 items
= [[k
, self
[k
]] for k
in self
]
82 tmp
= self
.__map
, self
.__end
83 del self
.__map
, self
.__end
84 inst_dict
= vars(self
).copy()
85 self
.__map
, self
.__end
= tmp
87 return (self
.__class
__, (items
,), inst_dict
)
88 return self
.__class
__, (items
,)
93 setdefault
= DictMixin
.setdefault
94 update
= DictMixin
.update
96 values
= DictMixin
.values
97 items
= DictMixin
.items
98 iterkeys
= DictMixin
.iterkeys
99 itervalues
= DictMixin
.itervalues
100 iteritems
= DictMixin
.iteritems
104 return '%s()' % (self
.__class
__.__name
__,)
105 return '%s(%r)' % (self
.__class
__.__name
__, self
.items())
108 return self
.__class
__(self
)
111 def fromkeys(cls
, iterable
, value
=None):
117 def __eq__(self
, other
):
118 if isinstance(other
, OrderedDict
):
119 if len(self
) != len(other
):
121 for p
, q
in zip(self
.items(), other
.items()):
125 return dict.__eq
__(self
, other
)
127 def __ne__(self
, other
):
128 return not self
== other