1 """Weak reference support for Python.
3 This module is an implementation of PEP 205:
5 http://python.sourceforge.net/peps/pep-0205.html
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.
14 from _weakref
import (
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
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
45 def __init__(self
, *args
, **kw
):
46 def remove(wr
, selfref
=ref(self
)):
51 UserDict
.UserDict
.__init
__(self
, *args
, **kw
)
53 def __getitem__(self
, key
):
60 def __contains__(self
, key
):
67 def has_key(self
, key
):
75 return "<WeakValueDictionary at %s>" % id(self
)
77 def __setitem__(self
, key
, value
):
78 self
.data
[key
] = KeyedRef(value
, self
._remove
, key
)
81 new
= WeakValueDictionary()
82 for key
, wr
in self
.data
.items():
88 def get(self
, key
, default
=None):
96 # This should only happen
103 for key
, wr
in self
.data
.items():
110 for wr
in self
.data
.itervalues():
112 if value
is not None:
116 return self
.data
.iterkeys()
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():
141 key
, wr
= self
.data
.popitem()
146 def pop(self
, key
, *args
):
148 o
= self
.data
.pop(key
)()
158 def setdefault(self
, key
, default
=None):
162 self
.data
[key
] = KeyedRef(default
, self
._remove
, key
)
167 def update(self
, dict=None, **kwargs
):
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
)
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()
191 for wr
in self
.data
.values():
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.
210 def __new__(type, ob
, callback
, key
):
211 self
= ref
.__new
__(type, ob
, callback
)
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
230 def __init__(self
, dict=None):
232 def remove(k
, selfref
=ref(self
)):
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
)]
246 return "<WeakKeyDictionary at %s>" % id(self
)
248 def __setitem__(self
, key
, value
):
249 self
.data
[ref(key
, self
._remove
)] = value
252 new
= WeakKeyDictionary()
253 for key
, value
in self
.data
.items():
259 def get(self
, key
, default
=None):
260 return self
.data
.get(ref(key
),default
)
262 def has_key(self
, key
):
267 return wr
in self
.data
269 def __contains__(self
, key
):
274 return wr
in self
.data
278 for key
, value
in self
.data
.items():
285 for wr
, value
in self
.data
.iteritems():
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()
303 for wr
in self
.data
.iterkeys():
309 return self
.iterkeys()
311 def itervalues(self
):
312 return self
.data
.itervalues()
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()
328 for wr
in self
.data
.keys():
336 key
, value
= self
.data
.popitem()
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
):
350 if not hasattr(dict, "items"):
351 dict = type({})(dict)
352 for key
, value
in dict.items():
353 d
[ref(key
, self
._remove
)] = value