weakref.py revision 4fd06e0170aa75e4873b73f733bfd3f3de19d967
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 ReferenceError, \ 20 CallableProxyType, \ 21 ProxyType, \ 22 ReferenceType 23 24ProxyTypes = (ProxyType, CallableProxyType) 25 26__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs", 27 "WeakKeyDictionary", "ReferenceType", "ProxyType", 28 "CallableProxyType", "ProxyTypes", "WeakValueDictionary"] 29 30 31class WeakValueDictionary(UserDict.UserDict): 32 """Mapping class that references values weakly. 33 34 Entries in the dictionary will be discarded when no strong 35 reference to the value exists anymore 36 """ 37 # We inherit the constructor without worrying about the input 38 # dictionary; since it uses our .update() method, we get the right 39 # checks (if the other dictionary is a WeakValueDictionary, 40 # objects are unwrapped on the way out, and we always wrap on the 41 # way in). 42 43 def __getitem__(self, key): 44 o = self.data[key]() 45 if o is None: 46 raise KeyError, key 47 else: 48 return o 49 50 def __repr__(self): 51 return "<WeakValueDictionary at %s>" % id(self) 52 53 def __setitem__(self, key, value): 54 def remove(o, data=self.data, key=key): 55 del data[key] 56 self.data[key] = ref(value, remove) 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 def remove(o, data=self.data, key=key): 109 del data[key] 110 self.data[key] = ref(default, remove) 111 return default 112 else: 113 return wr() 114 115 def update(self, dict): 116 d = self.data 117 for key, o in dict.items(): 118 def remove(o, data=d, key=key): 119 del data[key] 120 d[key] = ref(o, remove) 121 122 def values(self): 123 L = [] 124 for wr in self.data.values(): 125 o = wr() 126 if o is not None: 127 L.append(o) 128 return L 129 130 131class WeakKeyDictionary(UserDict.UserDict): 132 """ Mapping class that references keys weakly. 133 134 Entries in the dictionary will be discarded when there is no 135 longer a strong reference to the key. This can be used to 136 associate additional data with an object owned by other parts of 137 an application without adding attributes to those objects. This 138 can be especially useful with objects that override attribute 139 accesses. 140 """ 141 142 def __init__(self, dict=None): 143 self.data = {} 144 if dict is not None: self.update(dict) 145 def remove(k, data=self.data): 146 del data[k] 147 self._remove = remove 148 149 def __getitem__(self, key): 150 return self.data[ref(key)] 151 152 def __repr__(self): 153 return "<WeakKeyDictionary at %s>" % id(self) 154 155 def __setitem__(self, key, value): 156 self.data[ref(key, self._remove)] = value 157 158 def copy(self): 159 new = WeakKeyDictionary() 160 for key, value in self.data.items(): 161 o = key() 162 if o is not None: 163 new[o] = value 164 return new 165 166 def get(self, key, default=None): 167 return self.data.get(ref(key),default) 168 169 def has_key(self, key): 170 return self.data.has_key(ref(key)) 171 172 def items(self): 173 L = [] 174 for key, value in self.data.items(): 175 o = key() 176 if o is not None: 177 L.append((o, value)) 178 return L 179 180 def iteritems(self): 181 return WeakKeyedItemIterator(self) 182 183 def iterkeys(self): 184 return WeakKeyedKeyIterator(self) 185 __iter__ = iterkeys 186 187 def itervalues(self): 188 return self.data.itervalues() 189 190 def keys(self): 191 L = [] 192 for wr in self.data.keys(): 193 o = wr() 194 if o is not None: 195 L.append(o) 196 return L 197 198 def popitem(self): 199 while 1: 200 key, value = self.data.popitem() 201 o = key() 202 if o is not None: 203 return o, value 204 205 def setdefault(self, key, default): 206 return self.data.setdefault(ref(key, self._remove),default) 207 208 def update(self, dict): 209 d = self.data 210 for key, value in dict.items(): 211 d[ref(key, self._remove)] = value 212 213 214class BaseIter: 215 def __iter__(self): 216 return self 217 218 219class WeakKeyedKeyIterator(BaseIter): 220 def __init__(self, weakdict): 221 self._next = weakdict.data.iterkeys().next 222 223 def next(self): 224 while 1: 225 wr = self._next() 226 obj = wr() 227 if obj is not None: 228 return obj 229 230 231class WeakKeyedItemIterator(BaseIter): 232 def __init__(self, weakdict): 233 self._next = weakdict.data.iteritems().next 234 235 def next(self): 236 while 1: 237 wr, value = self._next() 238 key = wr() 239 if key is not None: 240 return key, value 241 242 243class WeakValuedValueIterator(BaseIter): 244 def __init__(self, weakdict): 245 self._next = weakdict.data.itervalues().next 246 247 def next(self): 248 while 1: 249 wr = self._next() 250 obj = wr() 251 if obj is not None: 252 return obj 253 254 255class WeakValuedItemIterator(BaseIter): 256 def __init__(self, weakdict): 257 self._next = weakdict.data.iteritems().next 258 259 def next(self): 260 while 1: 261 key, wr = self._next() 262 value = wr() 263 if value is not None: 264 return key, value 265 266 267# no longer needed 268del UserDict 269