Patch by Jeremy Katz (SF #1609407)
[python.git] / Lib / weakref.py
blob4f6d757fe3bb4a8a2efa38f5d7170713ed4649da
1 """Weak reference support for Python.
3 This module is an implementation of PEP 205:
5 http://python.sourceforge.net/peps/pep-0205.html
6 """
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.
12 import UserDict
14 from _weakref import (
15 getweakrefcount,
16 getweakrefs,
17 ref,
18 proxy,
19 CallableProxyType,
20 ProxyType,
21 ReferenceType)
23 from exceptions import ReferenceError
26 ProxyTypes = (ProxyType, CallableProxyType)
28 __all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
29 "WeakKeyDictionary", "ReferenceType", "ProxyType",
30 "CallableProxyType", "ProxyTypes", "WeakValueDictionary"]
33 class WeakValueDictionary(UserDict.UserDict):
34 """Mapping class that references values weakly.
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).
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)
53 def __getitem__(self, key):
54 o = self.data[key]()
55 if o is None:
56 raise KeyError, key
57 else:
58 return o
60 def __contains__(self, key):
61 try:
62 o = self.data[key]()
63 except KeyError:
64 return False
65 return o is not None
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
74 def __repr__(self):
75 return "<WeakValueDictionary at %s>" % id(self)
77 def __setitem__(self, key, value):
78 self.data[key] = KeyedRef(value, self._remove, key)
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
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
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
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
115 def iterkeys(self):
116 return self.data.iterkeys()
118 def __iter__(self):
119 return self.data.iterkeys()
121 def itervaluerefs(self):
122 """Return an iterator that yields the weak references to the values.
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.
131 return self.data.itervalues()
133 def itervalues(self):
134 for wr in self.data.itervalues():
135 obj = wr()
136 if obj is not None:
137 yield obj
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
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
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()
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)
177 def valuerefs(self):
178 """Return a list of weak references to the values.
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.
187 return self.data.values()
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
198 class KeyedRef(ref):
199 """Specialized reference that includes a key corresponding to the value.
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.
208 __slots__ = "key",
210 def __new__(type, ob, callback, key):
211 self = ref.__new__(type, ob, callback)
212 self.key = key
213 return self
215 def __init__(self, ob, callback, key):
216 super(KeyedRef, self).__init__(ob, callback)
219 class WeakKeyDictionary(UserDict.UserDict):
220 """ Mapping class that references keys weakly.
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.
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)
239 def __delitem__(self, key):
240 del self.data[ref(key)]
242 def __getitem__(self, key):
243 return self.data[ref(key)]
245 def __repr__(self):
246 return "<WeakKeyDictionary at %s>" % id(self)
248 def __setitem__(self, key, value):
249 self.data[ref(key, self._remove)] = value
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
259 def get(self, key, default=None):
260 return self.data.get(ref(key),default)
262 def has_key(self, key):
263 try:
264 wr = ref(key)
265 except TypeError:
266 return 0
267 return wr in self.data
269 def __contains__(self, key):
270 try:
271 wr = ref(key)
272 except TypeError:
273 return 0
274 return wr in self.data
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
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
290 def iterkeyrefs(self):
291 """Return an iterator that yields the weak references to the keys.
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.
300 return self.data.iterkeys()
302 def iterkeys(self):
303 for wr in self.data.iterkeys():
304 obj = wr()
305 if obj is not None:
306 yield obj
308 def __iter__(self):
309 return self.iterkeys()
311 def itervalues(self):
312 return self.data.itervalues()
314 def keyrefs(self):
315 """Return a list of weak references to the keys.
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.
324 return self.data.keys()
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
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
341 def pop(self, key, *args):
342 return self.data.pop(ref(key), *args)
344 def setdefault(self, key, default=None):
345 return self.data.setdefault(ref(key, self._remove),default)
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)