99# This software is distributed under the 3-clause BSD License.
1010# ___________________________________________________________________________
1111
12- import collections
13- from collections . abc import Mapping as collections_Mapping
12+ from collections . abc import Mapping , MutableMapping
13+
1414from pyomo .common .autoslots import AutoSlots
1515
16+ from ._hasher import hasher
17+
1618
1719def _rehash_keys (encode , val ):
1820 if encode :
1921 return val
2022 else :
2123 # object id() may have changed after unpickling,
2224 # so we rebuild the dictionary keys
23- return {_hasher [obj .__class__ ](obj ): (obj , v ) for obj , v in val .values ()}
24-
25-
26- class _Hasher (collections .defaultdict ):
27- def __init__ (self , * args , ** kwargs ):
28- super ().__init__ (lambda : self ._missing_impl , * args , ** kwargs )
29- self [tuple ] = self ._tuple
30-
31- def _missing_impl (self , val ):
32- try :
33- hash (val )
34- self [val .__class__ ] = self ._hashable
35- except :
36- self [val .__class__ ] = self ._unhashable
37- return self [val .__class__ ](val )
38-
39- @staticmethod
40- def _hashable (val ):
41- return val
42-
43- @staticmethod
44- def _unhashable (val ):
45- return id (val )
46-
47- def _tuple (self , val ):
48- return tuple (self [i .__class__ ](i ) for i in val )
49-
50- def hashable (self , obj , hashable = None ):
51- if isinstance (obj , type ):
52- cls = obj
53- else :
54- cls = type (obj )
55- if hashable is None :
56- fcn = self .get (cls , None )
57- if fcn is None :
58- raise KeyError (obj )
59- return fcn is self ._hashable
60- self [cls ] = self ._hashable if hashable else self ._unhashable
61-
62-
63- _hasher = _Hasher ()
25+ return {hasher [obj .__class__ ](obj ): (obj , v ) for obj , v in val .values ()}
6426
6527
66- class ComponentMap (AutoSlots .Mixin , collections . abc . MutableMapping ):
28+ class ComponentMap (AutoSlots .Mixin , MutableMapping ):
6729 """
6830 This class is a replacement for dict that allows Pyomo
6931 modeling components to be used as entry keys. The
@@ -89,9 +51,9 @@ class ComponentMap(AutoSlots.Mixin, collections.abc.MutableMapping):
8951 """
9052
9153 __slots__ = ("_dict" ,)
92- __autoslot_mappers__ = {' _dict' : _rehash_keys }
54+ __autoslot_mappers__ = {" _dict" : _rehash_keys }
9355 # Expose a "public" interface to the global _hasher dict
94- hasher = _hasher
56+ hasher = hasher
9557
9658 def __init__ (self , * args , ** kwds ):
9759 # maps id_hash(obj) -> (obj,val)
@@ -110,19 +72,19 @@ def __str__(self):
11072
11173 def __getitem__ (self , obj ):
11274 try :
113- return self ._dict [_hasher [obj .__class__ ](obj )][1 ]
75+ return self ._dict [hasher [obj .__class__ ](obj )][1 ]
11476 except KeyError :
115- _id = _hasher [obj .__class__ ](obj )
77+ _id = hasher [obj .__class__ ](obj )
11678 raise KeyError (f"{ obj } (key={ _id } )" ) from None
11779
11880 def __setitem__ (self , obj , val ):
119- self ._dict [_hasher [obj .__class__ ](obj )] = (obj , val )
81+ self ._dict [hasher [obj .__class__ ](obj )] = (obj , val )
12082
12183 def __delitem__ (self , obj ):
12284 try :
123- del self ._dict [_hasher [obj .__class__ ](obj )]
85+ del self ._dict [hasher [obj .__class__ ](obj )]
12486 except KeyError :
125- _id = _hasher [obj .__class__ ](obj )
87+ _id = hasher [obj .__class__ ](obj )
12688 raise KeyError (f"{ obj } (key={ _id } )" ) from None
12789
12890 def __iter__ (self ):
@@ -147,11 +109,11 @@ def update(self, *args, **kwargs):
147109 def __eq__ (self , other ):
148110 if self is other :
149111 return True
150- if not isinstance (other , collections_Mapping ) or len (self ) != len (other ):
112+ if not isinstance (other , Mapping ) or len (self ) != len (other ):
151113 return False
152114 # Note we have already verified the dicts are the same size
153115 for key , val in other .items ():
154- other_id = _hasher [key .__class__ ](key )
116+ other_id = hasher [key .__class__ ](key )
155117 if other_id not in self ._dict :
156118 return False
157119 self_val = self ._dict [other_id ][1 ]
@@ -174,20 +136,20 @@ def __ne__(self, other):
174136 #
175137
176138 def __contains__ (self , obj ):
177- return _hasher [obj .__class__ ](obj ) in self ._dict
139+ return hasher [obj .__class__ ](obj ) in self ._dict
178140
179141 def clear (self ):
180- ' D.clear() -> None. Remove all items from D.'
142+ " D.clear() -> None. Remove all items from D."
181143 self ._dict .clear ()
182144
183145 def get (self , key , default = None ):
184- ' D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.'
146+ " D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None."
185147 if key in self :
186148 return self [key ]
187149 return default
188150
189151 def setdefault (self , key , default = None ):
190- ' D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D'
152+ " D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D"
191153 if key in self :
192154 return self [key ]
193155 else :
@@ -204,7 +166,7 @@ class DefaultComponentMap(ComponentMap):
204166
205167 """
206168
207- __slots__ = (' default_factory' ,)
169+ __slots__ = (" default_factory" ,)
208170
209171 def __init__ (self , default_factory = None , * args , ** kwargs ):
210172 super ().__init__ (* args , ** kwargs )
@@ -217,7 +179,7 @@ def __missing__(self, key):
217179 return ans
218180
219181 def __getitem__ (self , obj ):
220- _key = _hasher [obj .__class__ ](obj )
182+ _key = hasher [obj .__class__ ](obj )
221183 if _key in self ._dict :
222184 return self ._dict [_key ][1 ]
223185 else :
0 commit comments