|
1 """Weak reference support for Python. |
|
2 |
|
3 This module is an implementation of PEP 205: |
|
4 |
|
5 http://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 |
|
12 import UserDict |
|
13 |
|
14 from _weakref import ( |
|
15 getweakrefcount, |
|
16 getweakrefs, |
|
17 ref, |
|
18 proxy, |
|
19 CallableProxyType, |
|
20 ProxyType, |
|
21 ReferenceType) |
|
22 |
|
23 from exceptions import ReferenceError |
|
24 |
|
25 |
|
26 ProxyTypes = (ProxyType, CallableProxyType) |
|
27 |
|
28 __all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs", |
|
29 "WeakKeyDictionary", "ReferenceError", "ReferenceType", "ProxyType", |
|
30 "CallableProxyType", "ProxyTypes", "WeakValueDictionary"] |
|
31 |
|
32 |
|
33 class 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 __init__(self, *args, **kw): |
|
46 def remove(wr, selfref=ref(self)): |
|
47 self = selfref() |
|
48 if self is not None: |
|
49 del self.data[wr.key] |
|
50 self._remove = remove |
|
51 UserDict.UserDict.__init__(self, *args, **kw) |
|
52 |
|
53 def __getitem__(self, key): |
|
54 o = self.data[key]() |
|
55 if o is None: |
|
56 raise KeyError, key |
|
57 else: |
|
58 return o |
|
59 |
|
60 def __contains__(self, key): |
|
61 try: |
|
62 o = self.data[key]() |
|
63 except KeyError: |
|
64 return False |
|
65 return o is not None |
|
66 |
|
67 def has_key(self, key): |
|
68 try: |
|
69 o = self.data[key]() |
|
70 except KeyError: |
|
71 return False |
|
72 return o is not None |
|
73 |
|
74 def __repr__(self): |
|
75 return "<WeakValueDictionary at %s>" % id(self) |
|
76 |
|
77 def __setitem__(self, key, value): |
|
78 self.data[key] = KeyedRef(value, self._remove, key) |
|
79 |
|
80 def copy(self): |
|
81 new = WeakValueDictionary() |
|
82 for key, wr in self.data.items(): |
|
83 o = wr() |
|
84 if o is not None: |
|
85 new[key] = o |
|
86 return new |
|
87 |
|
88 def get(self, key, default=None): |
|
89 try: |
|
90 wr = self.data[key] |
|
91 except KeyError: |
|
92 return default |
|
93 else: |
|
94 o = wr() |
|
95 if o is None: |
|
96 # This should only happen |
|
97 return default |
|
98 else: |
|
99 return o |
|
100 |
|
101 def items(self): |
|
102 L = [] |
|
103 for key, wr in self.data.items(): |
|
104 o = wr() |
|
105 if o is not None: |
|
106 L.append((key, o)) |
|
107 return L |
|
108 |
|
109 def iteritems(self): |
|
110 for wr in self.data.itervalues(): |
|
111 value = wr() |
|
112 if value is not None: |
|
113 yield wr.key, value |
|
114 |
|
115 def iterkeys(self): |
|
116 return self.data.iterkeys() |
|
117 |
|
118 def __iter__(self): |
|
119 return self.data.iterkeys() |
|
120 |
|
121 def itervaluerefs(self): |
|
122 """Return an iterator that yields the weak references to the values. |
|
123 |
|
124 The references are not guaranteed to be 'live' at the time |
|
125 they are used, so the result of calling the references needs |
|
126 to be checked before being used. This can be used to avoid |
|
127 creating references that will cause the garbage collector to |
|
128 keep the values around longer than needed. |
|
129 |
|
130 """ |
|
131 return self.data.itervalues() |
|
132 |
|
133 def itervalues(self): |
|
134 for wr in self.data.itervalues(): |
|
135 obj = wr() |
|
136 if obj is not None: |
|
137 yield obj |
|
138 |
|
139 def popitem(self): |
|
140 while 1: |
|
141 key, wr = self.data.popitem() |
|
142 o = wr() |
|
143 if o is not None: |
|
144 return key, o |
|
145 |
|
146 def pop(self, key, *args): |
|
147 try: |
|
148 o = self.data.pop(key)() |
|
149 except KeyError: |
|
150 if args: |
|
151 return args[0] |
|
152 raise |
|
153 if o is None: |
|
154 raise KeyError, key |
|
155 else: |
|
156 return o |
|
157 |
|
158 def setdefault(self, key, default=None): |
|
159 try: |
|
160 wr = self.data[key] |
|
161 except KeyError: |
|
162 self.data[key] = KeyedRef(default, self._remove, key) |
|
163 return default |
|
164 else: |
|
165 return wr() |
|
166 |
|
167 def update(self, dict=None, **kwargs): |
|
168 d = self.data |
|
169 if dict is not None: |
|
170 if not hasattr(dict, "items"): |
|
171 dict = type({})(dict) |
|
172 for key, o in dict.items(): |
|
173 d[key] = KeyedRef(o, self._remove, key) |
|
174 if len(kwargs): |
|
175 self.update(kwargs) |
|
176 |
|
177 def valuerefs(self): |
|
178 """Return a list of weak references to the values. |
|
179 |
|
180 The references are not guaranteed to be 'live' at the time |
|
181 they are used, so the result of calling the references needs |
|
182 to be checked before being used. This can be used to avoid |
|
183 creating references that will cause the garbage collector to |
|
184 keep the values around longer than needed. |
|
185 |
|
186 """ |
|
187 return self.data.values() |
|
188 |
|
189 def values(self): |
|
190 L = [] |
|
191 for wr in self.data.values(): |
|
192 o = wr() |
|
193 if o is not None: |
|
194 L.append(o) |
|
195 return L |
|
196 |
|
197 |
|
198 class KeyedRef(ref): |
|
199 """Specialized reference that includes a key corresponding to the value. |
|
200 |
|
201 This is used in the WeakValueDictionary to avoid having to create |
|
202 a function object for each key stored in the mapping. A shared |
|
203 callback object can use the 'key' attribute of a KeyedRef instead |
|
204 of getting a reference to the key from an enclosing scope. |
|
205 |
|
206 """ |
|
207 |
|
208 __slots__ = "key", |
|
209 |
|
210 def __new__(type, ob, callback, key): |
|
211 self = ref.__new__(type, ob, callback) |
|
212 self.key = key |
|
213 return self |
|
214 |
|
215 def __init__(self, ob, callback, key): |
|
216 super(KeyedRef, self).__init__(ob, callback) |
|
217 |
|
218 |
|
219 class WeakKeyDictionary(UserDict.UserDict): |
|
220 """ Mapping class that references keys weakly. |
|
221 |
|
222 Entries in the dictionary will be discarded when there is no |
|
223 longer a strong reference to the key. This can be used to |
|
224 associate additional data with an object owned by other parts of |
|
225 an application without adding attributes to those objects. This |
|
226 can be especially useful with objects that override attribute |
|
227 accesses. |
|
228 """ |
|
229 |
|
230 def __init__(self, dict=None): |
|
231 self.data = {} |
|
232 def remove(k, selfref=ref(self)): |
|
233 self = selfref() |
|
234 if self is not None: |
|
235 del self.data[k] |
|
236 self._remove = remove |
|
237 if dict is not None: self.update(dict) |
|
238 |
|
239 def __delitem__(self, key): |
|
240 del self.data[ref(key)] |
|
241 |
|
242 def __getitem__(self, key): |
|
243 return self.data[ref(key)] |
|
244 |
|
245 def __repr__(self): |
|
246 return "<WeakKeyDictionary at %s>" % id(self) |
|
247 |
|
248 def __setitem__(self, key, value): |
|
249 self.data[ref(key, self._remove)] = value |
|
250 |
|
251 def copy(self): |
|
252 new = WeakKeyDictionary() |
|
253 for key, value in self.data.items(): |
|
254 o = key() |
|
255 if o is not None: |
|
256 new[o] = value |
|
257 return new |
|
258 |
|
259 def get(self, key, default=None): |
|
260 return self.data.get(ref(key),default) |
|
261 |
|
262 def has_key(self, key): |
|
263 try: |
|
264 wr = ref(key) |
|
265 except TypeError: |
|
266 return 0 |
|
267 return wr in self.data |
|
268 |
|
269 def __contains__(self, key): |
|
270 try: |
|
271 wr = ref(key) |
|
272 except TypeError: |
|
273 return 0 |
|
274 return wr in self.data |
|
275 |
|
276 def items(self): |
|
277 L = [] |
|
278 for key, value in self.data.items(): |
|
279 o = key() |
|
280 if o is not None: |
|
281 L.append((o, value)) |
|
282 return L |
|
283 |
|
284 def iteritems(self): |
|
285 for wr, value in self.data.iteritems(): |
|
286 key = wr() |
|
287 if key is not None: |
|
288 yield key, value |
|
289 |
|
290 def iterkeyrefs(self): |
|
291 """Return an iterator that yields the weak references to the keys. |
|
292 |
|
293 The references are not guaranteed to be 'live' at the time |
|
294 they are used, so the result of calling the references needs |
|
295 to be checked before being used. This can be used to avoid |
|
296 creating references that will cause the garbage collector to |
|
297 keep the keys around longer than needed. |
|
298 |
|
299 """ |
|
300 return self.data.iterkeys() |
|
301 |
|
302 def iterkeys(self): |
|
303 for wr in self.data.iterkeys(): |
|
304 obj = wr() |
|
305 if obj is not None: |
|
306 yield obj |
|
307 |
|
308 def __iter__(self): |
|
309 return self.iterkeys() |
|
310 |
|
311 def itervalues(self): |
|
312 return self.data.itervalues() |
|
313 |
|
314 def keyrefs(self): |
|
315 """Return a list of weak references to the keys. |
|
316 |
|
317 The references are not guaranteed to be 'live' at the time |
|
318 they are used, so the result of calling the references needs |
|
319 to be checked before being used. This can be used to avoid |
|
320 creating references that will cause the garbage collector to |
|
321 keep the keys around longer than needed. |
|
322 |
|
323 """ |
|
324 return self.data.keys() |
|
325 |
|
326 def keys(self): |
|
327 L = [] |
|
328 for wr in self.data.keys(): |
|
329 o = wr() |
|
330 if o is not None: |
|
331 L.append(o) |
|
332 return L |
|
333 |
|
334 def popitem(self): |
|
335 while 1: |
|
336 key, value = self.data.popitem() |
|
337 o = key() |
|
338 if o is not None: |
|
339 return o, value |
|
340 |
|
341 def pop(self, key, *args): |
|
342 return self.data.pop(ref(key), *args) |
|
343 |
|
344 def setdefault(self, key, default=None): |
|
345 return self.data.setdefault(ref(key, self._remove),default) |
|
346 |
|
347 def update(self, dict=None, **kwargs): |
|
348 d = self.data |
|
349 if dict is not None: |
|
350 if not hasattr(dict, "items"): |
|
351 dict = type({})(dict) |
|
352 for key, value in dict.items(): |
|
353 d[ref(key, self._remove)] = value |
|
354 if len(kwargs): |
|
355 self.update(kwargs) |