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 itervalues(self
):
122 for wr
in self
.data
.itervalues():
129 key
, wr
= self
.data
.popitem()
134 def pop(self
, key
, *args
):
136 o
= self
.data
.pop(key
)()
146 def setdefault(self
, key
, default
=None):
150 self
.data
[key
] = KeyedRef(default
, self
._remove
, key
)
155 def update(self
, dict=None, **kwargs
):
158 if not hasattr(dict, "items"):
159 dict = type({})(dict)
160 for key
, o
in dict.items():
161 d
[key
] = KeyedRef(o
, self
._remove
, key
)
167 for wr
in self
.data
.values():
175 """Specialized reference that includes a key corresponding to the value.
177 This is used in the WeakValueDictionary to avoid having to create
178 a function object for each key stored in the mapping. A shared
179 callback object can use the 'key' attribute of a KeyedRef instead
180 of getting a reference to the key from an enclosing scope.
186 def __new__(type, ob
, callback
, key
):
187 self
= ref
.__new
__(type, ob
, callback
)
191 def __init__(self
, ob
, callback
, key
):
192 super(KeyedRef
, self
).__init
__(ob
, callback
)
195 class WeakKeyDictionary(UserDict
.UserDict
):
196 """ Mapping class that references keys weakly.
198 Entries in the dictionary will be discarded when there is no
199 longer a strong reference to the key. This can be used to
200 associate additional data with an object owned by other parts of
201 an application without adding attributes to those objects. This
202 can be especially useful with objects that override attribute
206 def __init__(self
, dict=None):
208 def remove(k
, selfref
=ref(self
)):
212 self
._remove
= remove
213 if dict is not None: self
.update(dict)
215 def __delitem__(self
, key
):
216 del self
.data
[ref(key
)]
218 def __getitem__(self
, key
):
219 return self
.data
[ref(key
)]
222 return "<WeakKeyDictionary at %s>" % id(self
)
224 def __setitem__(self
, key
, value
):
225 self
.data
[ref(key
, self
._remove
)] = value
228 new
= WeakKeyDictionary()
229 for key
, value
in self
.data
.items():
235 def get(self
, key
, default
=None):
236 return self
.data
.get(ref(key
),default
)
238 def has_key(self
, key
):
243 return wr
in self
.data
245 def __contains__(self
, key
):
250 return wr
in self
.data
254 for key
, value
in self
.data
.items():
261 for wr
, value
in self
.data
.iteritems():
267 for wr
in self
.data
.iterkeys():
273 return self
.iterkeys()
275 def itervalues(self
):
276 return self
.data
.itervalues()
280 for wr
in self
.data
.keys():
288 key
, value
= self
.data
.popitem()
293 def pop(self
, key
, *args
):
294 return self
.data
.pop(ref(key
), *args
)
296 def setdefault(self
, key
, default
=None):
297 return self
.data
.setdefault(ref(key
, self
._remove
),default
)
299 def update(self
, dict=None, **kwargs
):
302 if not hasattr(dict, "items"):
303 dict = type({})(dict)
304 for key
, value
in dict.items():
305 d
[ref(key
, self
._remove
)] = value