weakref.py revision c411dbaeee29dba87d5432a92fe76ea65d8e25f0
1"""Weak reference support for Python. 2 3This module is an implementation of PEP 205: 4 5http://python.sourceforge.net/peps/pep-0205.html 6""" 7 8# Naming convention: Variables named "wr" are weak reference objects; 9# they are called this instead of "ref" to avoid name collisions with 10# the module-global ref() function imported from _weakref. 11 12import UserDict 13 14from _weakref import \ 15 getweakrefcount, \ 16 getweakrefs, \ 17 ref, \ 18 proxy, \ 19 CallableProxyType, \ 20 ProxyType, \ 21 ReferenceType 22 23from exceptions import ReferenceError 24 25 26ProxyTypes = (ProxyType, CallableProxyType) 27 28__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs", 29 "WeakKeyDictionary", "ReferenceType", "ProxyType", 30 "CallableProxyType", "ProxyTypes", "WeakValueDictionary"] 31 32 33class WeakValueDictionary(UserDict.UserDict): 34 """Mapping class that references values weakly. 35 36 Entries in the dictionary will be discarded when no strong 37 reference to the value exists anymore 38 """ 39 # We inherit the constructor without worrying about the input 40 # dictionary; since it uses our .update() method, we get the right 41 # checks (if the other dictionary is a WeakValueDictionary, 42 # objects are unwrapped on the way out, and we always wrap on the 43 # way in). 44 45 def __getitem__(self, key): 46 o = self.data[key]() 47 if o is None: 48 raise KeyError, key 49 else: 50 return o 51 52 def __repr__(self): 53 return "<WeakValueDictionary at %s>" % id(self) 54 55 def __setitem__(self, key, value): 56 self.data[key] = ref(value, self.__makeremove(key)) 57 58 def copy(self): 59 new = WeakValueDictionary() 60 for key, wr in self.data.items(): 61 o = wr() 62 if o is not None: 63 new[key] = o 64 return new 65 66 def get(self, key, default=None): 67 try: 68 wr = self.data[key] 69 except KeyError: 70 return default 71 else: 72 o = wr() 73 if o is None: 74 # This should only happen 75 return default 76 else: 77 return o 78 79 def items(self): 80 L = [] 81 for key, wr in self.data.items(): 82 o = wr() 83 if o is not None: 84 L.append((key, o)) 85 return L 86 87 def iteritems(self): 88 return WeakValuedItemIterator(self) 89 90 def iterkeys(self): 91 return self.data.iterkeys() 92 __iter__ = iterkeys 93 94 def itervalues(self): 95 return WeakValuedValueIterator(self) 96 97 def popitem(self): 98 while 1: 99 key, wr = self.data.popitem() 100 o = wr() 101 if o is not None: 102 return key, o 103 104 def setdefault(self, key, default): 105 try: 106 wr = self.data[key] 107 except KeyError: 108 self.data[key] = ref(default, self.__makeremove(key)) 109 return default 110 else: 111 return wr() 112 113 def update(self, dict): 114 d = self.data 115 for key, o in dict.items(): 116 d[key] = ref(o, self.__makeremove(key)) 117 118 def values(self): 119 L = [] 120 for wr in self.data.values(): 121 o = wr() 122 if o is not None: 123 L.append(o) 124 return L 125 126 def __makeremove(self, key): 127 def remove(o, selfref=ref(self), key=key): 128 self = selfref() 129 if self is not None: 130 del self.data[key] 131 return remove 132 133 134class WeakKeyDictionary(UserDict.UserDict): 135 """ Mapping class that references keys weakly. 136 137 Entries in the dictionary will be discarded when there is no 138 longer a strong reference to the key. This can be used to 139 associate additional data with an object owned by other parts of 140 an application without adding attributes to those objects. This 141 can be especially useful with objects that override attribute 142 accesses. 143 """ 144 145 def __init__(self, dict=None): 146 self.data = {} 147 def remove(k, selfref=ref(self)): 148 self = selfref() 149 if self is not None: 150 del self.data[k] 151 self._remove = remove 152 if dict is not None: self.update(dict) 153 154 def __delitem__(self, key): 155 for ref in self.data.iterkeys(): 156 o = ref() 157 if o == key: 158 del self.data[ref] 159 return 160 161 def __getitem__(self, key): 162 return self.data[ref(key)] 163 164 def __repr__(self): 165 return "<WeakKeyDictionary at %s>" % id(self) 166 167 def __setitem__(self, key, value): 168 self.data[ref(key, self._remove)] = value 169 170 def copy(self): 171 new = WeakKeyDictionary() 172 for key, value in self.data.items(): 173 o = key() 174 if o is not None: 175 new[o] = value 176 return new 177 178 def get(self, key, default=None): 179 return self.data.get(ref(key),default) 180 181 def has_key(self, key): 182 try: 183 wr = ref(key) 184 except TypeError: 185 return 0 186 return wr in self.data 187 188 def __contains__(self, key): 189 try: 190 wr = ref(key) 191 except TypeError: 192 return 0 193 return wr in self.data 194 195 def items(self): 196 L = [] 197 for key, value in self.data.items(): 198 o = key() 199 if o is not None: 200 L.append((o, value)) 201 return L 202 203 def iteritems(self): 204 return WeakKeyedItemIterator(self) 205 206 def iterkeys(self): 207 return WeakKeyedKeyIterator(self) 208 __iter__ = iterkeys 209 210 def itervalues(self): 211 return self.data.itervalues() 212 213 def keys(self): 214 L = [] 215 for wr in self.data.keys(): 216 o = wr() 217 if o is not None: 218 L.append(o) 219 return L 220 221 def popitem(self): 222 while 1: 223 key, value = self.data.popitem() 224 o = key() 225 if o is not None: 226 return o, value 227 228 def setdefault(self, key, default): 229 return self.data.setdefault(ref(key, self._remove),default) 230 231 def update(self, dict): 232 d = self.data 233 for key, value in dict.items(): 234 d[ref(key, self._remove)] = value 235 236 237class BaseIter: 238 def __iter__(self): 239 return self 240 241 242class WeakKeyedKeyIterator(BaseIter): 243 def __init__(self, weakdict): 244 self._next = weakdict.data.iterkeys().next 245 246 def next(self): 247 while 1: 248 wr = self._next() 249 obj = wr() 250 if obj is not None: 251 return obj 252 253 254class WeakKeyedItemIterator(BaseIter): 255 def __init__(self, weakdict): 256 self._next = weakdict.data.iteritems().next 257 258 def next(self): 259 while 1: 260 wr, value = self._next() 261 key = wr() 262 if key is not None: 263 return key, value 264 265 266class WeakValuedValueIterator(BaseIter): 267 def __init__(self, weakdict): 268 self._next = weakdict.data.itervalues().next 269 270 def next(self): 271 while 1: 272 wr = self._next() 273 obj = wr() 274 if obj is not None: 275 return obj 276 277 278class WeakValuedItemIterator(BaseIter): 279 def __init__(self, weakdict): 280 self._next = weakdict.data.iteritems().next 281 282 def next(self): 283 while 1: 284 key, wr = self._next() 285 value = wr() 286 if value is not None: 287 return key, value 288 289 290# no longer needed 291del UserDict 292