weakref.py revision 39b17c513ae7b9baecdc8292876683647186fee4
1"""Weak reference support for Python. 2 3This module is an implementation of PEP 205: 4 5http://www.python.org/dev/peps/pep-0205/ 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 12from _weakref import ( 13 getweakrefcount, 14 getweakrefs, 15 ref, 16 proxy, 17 CallableProxyType, 18 ProxyType, 19 ReferenceType) 20 21from _weakrefset import WeakSet, _IterationGuard 22 23import collections # Import after _weakref to avoid circular import. 24 25ProxyTypes = (ProxyType, CallableProxyType) 26 27__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs", 28 "WeakKeyDictionary", "ReferenceType", "ProxyType", 29 "CallableProxyType", "ProxyTypes", "WeakValueDictionary", 30 "WeakSet", "WeakMethod"] 31 32 33class WeakMethod(ref): 34 """ 35 A custom `weakref.ref` subclass which simulates a weak reference to 36 a bound method, working around the lifetime problem of bound methods. 37 """ 38 39 __slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__" 40 41 def __new__(cls, meth, callback=None): 42 try: 43 obj = meth.__self__ 44 func = meth.__func__ 45 except AttributeError: 46 raise TypeError("argument should be a bound method, not {}" 47 .format(type(meth))) from None 48 def _cb(arg): 49 # The self-weakref trick is needed to avoid creating a reference 50 # cycle. 51 self = self_wr() 52 if self._alive: 53 self._alive = False 54 if callback is not None: 55 callback(self) 56 self = ref.__new__(cls, obj, _cb) 57 self._func_ref = ref(func, _cb) 58 self._meth_type = type(meth) 59 self._alive = True 60 self_wr = ref(self) 61 return self 62 63 def __call__(self): 64 obj = super().__call__() 65 func = self._func_ref() 66 if obj is None or func is None: 67 return None 68 return self._meth_type(func, obj) 69 70 def __eq__(self, other): 71 if isinstance(other, WeakMethod): 72 if not self._alive or not other._alive: 73 return self is other 74 return ref.__eq__(self, other) and self._func_ref == other._func_ref 75 return False 76 77 def __ne__(self, other): 78 if isinstance(other, WeakMethod): 79 if not self._alive or not other._alive: 80 return self is not other 81 return ref.__ne__(self, other) or self._func_ref != other._func_ref 82 return True 83 84 __hash__ = ref.__hash__ 85 86 87class WeakValueDictionary(collections.MutableMapping): 88 """Mapping class that references values weakly. 89 90 Entries in the dictionary will be discarded when no strong 91 reference to the value exists anymore 92 """ 93 # We inherit the constructor without worrying about the input 94 # dictionary; since it uses our .update() method, we get the right 95 # checks (if the other dictionary is a WeakValueDictionary, 96 # objects are unwrapped on the way out, and we always wrap on the 97 # way in). 98 99 def __init__(self, *args, **kw): 100 def remove(wr, selfref=ref(self)): 101 self = selfref() 102 if self is not None: 103 if self._iterating: 104 self._pending_removals.append(wr.key) 105 else: 106 del self.data[wr.key] 107 self._remove = remove 108 # A list of keys to be removed 109 self._pending_removals = [] 110 self._iterating = set() 111 self.data = d = {} 112 self.update(*args, **kw) 113 114 def _commit_removals(self): 115 l = self._pending_removals 116 d = self.data 117 # We shouldn't encounter any KeyError, because this method should 118 # always be called *before* mutating the dict. 119 while l: 120 del d[l.pop()] 121 122 def __getitem__(self, key): 123 o = self.data[key]() 124 if o is None: 125 raise KeyError(key) 126 else: 127 return o 128 129 def __delitem__(self, key): 130 if self._pending_removals: 131 self._commit_removals() 132 del self.data[key] 133 134 def __len__(self): 135 return len(self.data) - len(self._pending_removals) 136 137 def __contains__(self, key): 138 try: 139 o = self.data[key]() 140 except KeyError: 141 return False 142 return o is not None 143 144 def __repr__(self): 145 return "<WeakValueDictionary at %s>" % id(self) 146 147 def __setitem__(self, key, value): 148 if self._pending_removals: 149 self._commit_removals() 150 self.data[key] = KeyedRef(value, self._remove, key) 151 152 def copy(self): 153 new = WeakValueDictionary() 154 for key, wr in self.data.items(): 155 o = wr() 156 if o is not None: 157 new[key] = o 158 return new 159 160 __copy__ = copy 161 162 def __deepcopy__(self, memo): 163 from copy import deepcopy 164 new = self.__class__() 165 for key, wr in self.data.items(): 166 o = wr() 167 if o is not None: 168 new[deepcopy(key, memo)] = o 169 return new 170 171 def get(self, key, default=None): 172 try: 173 wr = self.data[key] 174 except KeyError: 175 return default 176 else: 177 o = wr() 178 if o is None: 179 # This should only happen 180 return default 181 else: 182 return o 183 184 def items(self): 185 with _IterationGuard(self): 186 for k, wr in self.data.items(): 187 v = wr() 188 if v is not None: 189 yield k, v 190 191 def keys(self): 192 with _IterationGuard(self): 193 for k, wr in self.data.items(): 194 if wr() is not None: 195 yield k 196 197 __iter__ = keys 198 199 def itervaluerefs(self): 200 """Return an iterator that yields the weak references to the values. 201 202 The references are not guaranteed to be 'live' at the time 203 they are used, so the result of calling the references needs 204 to be checked before being used. This can be used to avoid 205 creating references that will cause the garbage collector to 206 keep the values around longer than needed. 207 208 """ 209 with _IterationGuard(self): 210 yield from self.data.values() 211 212 def values(self): 213 with _IterationGuard(self): 214 for wr in self.data.values(): 215 obj = wr() 216 if obj is not None: 217 yield obj 218 219 def popitem(self): 220 if self._pending_removals: 221 self._commit_removals() 222 while True: 223 key, wr = self.data.popitem() 224 o = wr() 225 if o is not None: 226 return key, o 227 228 def pop(self, key, *args): 229 if self._pending_removals: 230 self._commit_removals() 231 try: 232 o = self.data.pop(key)() 233 except KeyError: 234 if args: 235 return args[0] 236 raise 237 if o is None: 238 raise KeyError(key) 239 else: 240 return o 241 242 def setdefault(self, key, default=None): 243 try: 244 wr = self.data[key] 245 except KeyError: 246 if self._pending_removals: 247 self._commit_removals() 248 self.data[key] = KeyedRef(default, self._remove, key) 249 return default 250 else: 251 return wr() 252 253 def update(self, dict=None, **kwargs): 254 if self._pending_removals: 255 self._commit_removals() 256 d = self.data 257 if dict is not None: 258 if not hasattr(dict, "items"): 259 dict = type({})(dict) 260 for key, o in dict.items(): 261 d[key] = KeyedRef(o, self._remove, key) 262 if len(kwargs): 263 self.update(kwargs) 264 265 def valuerefs(self): 266 """Return a list of weak references to the values. 267 268 The references are not guaranteed to be 'live' at the time 269 they are used, so the result of calling the references needs 270 to be checked before being used. This can be used to avoid 271 creating references that will cause the garbage collector to 272 keep the values around longer than needed. 273 274 """ 275 return list(self.data.values()) 276 277 278class KeyedRef(ref): 279 """Specialized reference that includes a key corresponding to the value. 280 281 This is used in the WeakValueDictionary to avoid having to create 282 a function object for each key stored in the mapping. A shared 283 callback object can use the 'key' attribute of a KeyedRef instead 284 of getting a reference to the key from an enclosing scope. 285 286 """ 287 288 __slots__ = "key", 289 290 def __new__(type, ob, callback, key): 291 self = ref.__new__(type, ob, callback) 292 self.key = key 293 return self 294 295 def __init__(self, ob, callback, key): 296 super().__init__(ob, callback) 297 298 299class WeakKeyDictionary(collections.MutableMapping): 300 """ Mapping class that references keys weakly. 301 302 Entries in the dictionary will be discarded when there is no 303 longer a strong reference to the key. This can be used to 304 associate additional data with an object owned by other parts of 305 an application without adding attributes to those objects. This 306 can be especially useful with objects that override attribute 307 accesses. 308 """ 309 310 def __init__(self, dict=None): 311 self.data = {} 312 def remove(k, selfref=ref(self)): 313 self = selfref() 314 if self is not None: 315 if self._iterating: 316 self._pending_removals.append(k) 317 else: 318 del self.data[k] 319 self._remove = remove 320 # A list of dead weakrefs (keys to be removed) 321 self._pending_removals = [] 322 self._iterating = set() 323 if dict is not None: 324 self.update(dict) 325 326 def _commit_removals(self): 327 # NOTE: We don't need to call this method before mutating the dict, 328 # because a dead weakref never compares equal to a live weakref, 329 # even if they happened to refer to equal objects. 330 # However, it means keys may already have been removed. 331 l = self._pending_removals 332 d = self.data 333 while l: 334 try: 335 del d[l.pop()] 336 except KeyError: 337 pass 338 339 def __delitem__(self, key): 340 del self.data[ref(key)] 341 342 def __getitem__(self, key): 343 return self.data[ref(key)] 344 345 def __len__(self): 346 return len(self.data) - len(self._pending_removals) 347 348 def __repr__(self): 349 return "<WeakKeyDictionary at %s>" % id(self) 350 351 def __setitem__(self, key, value): 352 self.data[ref(key, self._remove)] = value 353 354 def copy(self): 355 new = WeakKeyDictionary() 356 for key, value in self.data.items(): 357 o = key() 358 if o is not None: 359 new[o] = value 360 return new 361 362 __copy__ = copy 363 364 def __deepcopy__(self, memo): 365 from copy import deepcopy 366 new = self.__class__() 367 for key, value in self.data.items(): 368 o = key() 369 if o is not None: 370 new[o] = deepcopy(value, memo) 371 return new 372 373 def get(self, key, default=None): 374 return self.data.get(ref(key),default) 375 376 def __contains__(self, key): 377 try: 378 wr = ref(key) 379 except TypeError: 380 return False 381 return wr in self.data 382 383 def items(self): 384 with _IterationGuard(self): 385 for wr, value in self.data.items(): 386 key = wr() 387 if key is not None: 388 yield key, value 389 390 def keys(self): 391 with _IterationGuard(self): 392 for wr in self.data: 393 obj = wr() 394 if obj is not None: 395 yield obj 396 397 __iter__ = keys 398 399 def values(self): 400 with _IterationGuard(self): 401 for wr, value in self.data.items(): 402 if wr() is not None: 403 yield value 404 405 def keyrefs(self): 406 """Return a list of weak references to the keys. 407 408 The references are not guaranteed to be 'live' at the time 409 they are used, so the result of calling the references needs 410 to be checked before being used. This can be used to avoid 411 creating references that will cause the garbage collector to 412 keep the keys around longer than needed. 413 414 """ 415 return list(self.data) 416 417 def popitem(self): 418 while True: 419 key, value = self.data.popitem() 420 o = key() 421 if o is not None: 422 return o, value 423 424 def pop(self, key, *args): 425 return self.data.pop(ref(key), *args) 426 427 def setdefault(self, key, default=None): 428 return self.data.setdefault(ref(key, self._remove),default) 429 430 def update(self, dict=None, **kwargs): 431 d = self.data 432 if dict is not None: 433 if not hasattr(dict, "items"): 434 dict = type({})(dict) 435 for key, value in dict.items(): 436 d[ref(key, self._remove)] = value 437 if len(kwargs): 438 self.update(kwargs) 439