1111from keyword import iskeyword as _iskeyword
1212import sys as _sys
1313import heapq as _heapq
14- from weakref import proxy as _proxy
1514from itertools import repeat as _repeat , chain as _chain , starmap as _starmap
1615
1716################################################################################
1817### OrderedDict
1918################################################################################
2019
21- class _Link (object ):
22- __slots__ = 'prev' , 'next' , 'key' , '__weakref__'
23-
2420class OrderedDict (dict , MutableMapping ):
2521 'Dictionary that remembers insertion order'
2622 # An inherited dict maps keys to values.
@@ -31,9 +27,7 @@ class OrderedDict(dict, MutableMapping):
3127 # The internal self.__map dictionary maps keys to links in a doubly linked list.
3228 # The circular doubly linked list starts and ends with a sentinel element.
3329 # The sentinel element never gets deleted (this simplifies the algorithm).
34- # The prev/next links are weakref proxies (to prevent circular references).
35- # Individual links are kept alive by the hard reference in self.__map.
36- # Those hard references disappear when a key is deleted from an OrderedDict.
30+ # Each link is stored as a list of length three: [PREV, NEXT, KEY].
3731
3832 def __init__ (self , * args , ** kwds ):
3933 '''Initialize an ordered dictionary. Signature is the same as for
@@ -46,56 +40,51 @@ def __init__(self, *args, **kwds):
4640 try :
4741 self .__root
4842 except AttributeError :
49- self .__root = root = _Link () # sentinel node for the doubly linked list
50- root .prev = root .next = root
43+ self .__root = root = [None , None , None ] # sentinel node
44+ PREV = 0
45+ NEXT = 1
46+ root [PREV ] = root [NEXT ] = root
5147 self .__map = {}
5248 self .update (* args , ** kwds )
5349
54- def clear (self ):
55- 'od.clear() -> None. Remove all items from od.'
56- root = self .__root
57- root .prev = root .next = root
58- self .__map .clear ()
59- dict .clear (self )
60-
61- def __setitem__ (self , key , value ):
50+ def __setitem__ (self , key , value , PREV = 0 , NEXT = 1 , dict_setitem = dict .__setitem__ ):
6251 'od.__setitem__(i, y) <==> od[i]=y'
6352 # Setting a new item creates a new link which goes at the end of the linked
6453 # list, and the inherited dictionary is updated with the new key/value pair.
6554 if key not in self :
66- self .__map [key ] = link = _Link ()
6755 root = self .__root
68- last = root .prev
69- link .prev , link .next , link .key = last , root , key
70- last .next = root .prev = _proxy (link )
71- dict .__setitem__ (self , key , value )
56+ last = root [PREV ]
57+ last [NEXT ] = root [PREV ] = self .__map [key ] = [last , root , key ]
58+ dict_setitem (self , key , value )
7259
73- def __delitem__ (self , key ):
60+ def __delitem__ (self , key , PREV = 0 , NEXT = 1 , dict_delitem = dict . __delitem__ ):
7461 'od.__delitem__(y) <==> del od[y]'
7562 # Deleting an existing item uses self.__map to find the link which is
7663 # then removed by updating the links in the predecessor and successor nodes.
77- dict . __delitem__ (self , key )
64+ dict_delitem (self , key )
7865 link = self .__map .pop (key )
79- link .prev .next = link .next
80- link .next .prev = link .prev
66+ link_prev = link [PREV ]
67+ link_next = link [NEXT ]
68+ link_prev [NEXT ] = link_next
69+ link_next [PREV ] = link_prev
8170
82- def __iter__ (self ):
71+ def __iter__ (self , NEXT = 1 , KEY = 2 ):
8372 'od.__iter__() <==> iter(od)'
8473 # Traverse the linked list in order.
8574 root = self .__root
86- curr = root . next
75+ curr = root [ NEXT ]
8776 while curr is not root :
88- yield curr . key
89- curr = curr . next
77+ yield curr [ KEY ]
78+ curr = curr [ NEXT ]
9079
91- def __reversed__ (self ):
80+ def __reversed__ (self , PREV = 0 , KEY = 2 ):
9281 'od.__reversed__() <==> reversed(od)'
9382 # Traverse the linked list in reverse order.
9483 root = self .__root
95- curr = root . prev
84+ curr = root [ PREV ]
9685 while curr is not root :
97- yield curr . key
98- curr = curr . prev
86+ yield curr [ KEY ]
87+ curr = curr [ PREV ]
9988
10089 def __reduce__ (self ):
10190 'Return state information for pickling'
@@ -108,12 +97,24 @@ def __reduce__(self):
10897 return (self .__class__ , (items ,), inst_dict )
10998 return self .__class__ , (items ,)
11099
100+ def clear (self ):
101+ 'od.clear() -> None. Remove all items from od.'
102+ try :
103+ for node in self .__map .values ():
104+ del node [:]
105+ self .__root [:] = [self .__root , self .__root , None ]
106+ self .__map .clear ()
107+ except AttributeError :
108+ pass
109+ dict .clear (self )
110+
111111 setdefault = MutableMapping .setdefault
112112 update = MutableMapping .update
113113 pop = MutableMapping .pop
114114 keys = MutableMapping .keys
115115 values = MutableMapping .values
116116 items = MutableMapping .items
117+ __ne__ = MutableMapping .__ne__
117118
118119 def popitem (self , last = True ):
119120 '''od.popitem() -> (k, v), return and remove a (key, value) pair.
@@ -157,13 +158,8 @@ def __eq__(self, other):
157158 all (p == q for p , q in zip (self .items (), other .items ()))
158159 return dict .__eq__ (self , other )
159160
160- def __ne__ (self , other ):
161- '''od.__ne__(y) <==> od!=y. Comparison to another OD is order-sensitive
162- while comparison to a regular mapping is order-insensitive.
163-
164- '''
165- return not self == other
166-
161+ def __del__ (self ):
162+ self .clear () # eliminate cyclical references
167163
168164
169165################################################################################
0 commit comments