This commit was manufactured by cvs2svn to create tag 'r23b1-mac'.
[python/dscho.git] / Lib / weakref.py
blob838ff5ef7a5bbaff88b0fd8927a6be09146f31a4
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 __getitem__(self, key):
46 o = self.data[key]()
47 if o is None:
48 raise KeyError, key
49 else:
50 return o
52 def __repr__(self):
53 return "<WeakValueDictionary at %s>" % id(self)
55 def __setitem__(self, key, value):
56 self.data[key] = ref(value, self.__makeremove(key))
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
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
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
87 def iteritems(self):
88 return WeakValuedItemIterator(self)
90 def iterkeys(self):
91 return self.data.iterkeys()
92 __iter__ = iterkeys
94 def itervalues(self):
95 return WeakValuedValueIterator(self)
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
104 def pop(self, key, *args):
105 try:
106 o = self.data.pop(key)()
107 except KeyError:
108 if args:
109 return args[0]
110 raise
111 if o is None:
112 raise KeyError, key
113 else:
114 return o
116 def setdefault(self, key, default):
117 try:
118 wr = self.data[key]
119 except KeyError:
120 self.data[key] = ref(default, self.__makeremove(key))
121 return default
122 else:
123 return wr()
125 def update(self, dict):
126 d = self.data
127 for key, o in dict.items():
128 d[key] = ref(o, self.__makeremove(key))
130 def values(self):
131 L = []
132 for wr in self.data.values():
133 o = wr()
134 if o is not None:
135 L.append(o)
136 return L
138 def __makeremove(self, key):
139 def remove(o, selfref=ref(self), key=key):
140 self = selfref()
141 if self is not None:
142 del self.data[key]
143 return remove
146 class WeakKeyDictionary(UserDict.UserDict):
147 """ Mapping class that references keys weakly.
149 Entries in the dictionary will be discarded when there is no
150 longer a strong reference to the key. This can be used to
151 associate additional data with an object owned by other parts of
152 an application without adding attributes to those objects. This
153 can be especially useful with objects that override attribute
154 accesses.
157 def __init__(self, dict=None):
158 self.data = {}
159 def remove(k, selfref=ref(self)):
160 self = selfref()
161 if self is not None:
162 del self.data[k]
163 self._remove = remove
164 if dict is not None: self.update(dict)
166 def __delitem__(self, key):
167 for ref in self.data.iterkeys():
168 o = ref()
169 if o == key:
170 del self.data[ref]
171 return
173 def __getitem__(self, key):
174 return self.data[ref(key)]
176 def __repr__(self):
177 return "<WeakKeyDictionary at %s>" % id(self)
179 def __setitem__(self, key, value):
180 self.data[ref(key, self._remove)] = value
182 def copy(self):
183 new = WeakKeyDictionary()
184 for key, value in self.data.items():
185 o = key()
186 if o is not None:
187 new[o] = value
188 return new
190 def get(self, key, default=None):
191 return self.data.get(ref(key),default)
193 def has_key(self, key):
194 try:
195 wr = ref(key)
196 except TypeError:
197 return 0
198 return wr in self.data
200 def __contains__(self, key):
201 try:
202 wr = ref(key)
203 except TypeError:
204 return 0
205 return wr in self.data
207 def items(self):
208 L = []
209 for key, value in self.data.items():
210 o = key()
211 if o is not None:
212 L.append((o, value))
213 return L
215 def iteritems(self):
216 return WeakKeyedItemIterator(self)
218 def iterkeys(self):
219 return WeakKeyedKeyIterator(self)
220 __iter__ = iterkeys
222 def itervalues(self):
223 return self.data.itervalues()
225 def keys(self):
226 L = []
227 for wr in self.data.keys():
228 o = wr()
229 if o is not None:
230 L.append(o)
231 return L
233 def popitem(self):
234 while 1:
235 key, value = self.data.popitem()
236 o = key()
237 if o is not None:
238 return o, value
240 def pop(self, key, *args):
241 return self.data.pop(ref(key), *args)
243 def setdefault(self, key, default):
244 return self.data.setdefault(ref(key, self._remove),default)
246 def update(self, dict):
247 d = self.data
248 for key, value in dict.items():
249 d[ref(key, self._remove)] = value
252 class BaseIter:
253 def __iter__(self):
254 return self
257 class WeakKeyedKeyIterator(BaseIter):
258 def __init__(self, weakdict):
259 self._next = weakdict.data.iterkeys().next
261 def next(self):
262 while 1:
263 wr = self._next()
264 obj = wr()
265 if obj is not None:
266 return obj
269 class WeakKeyedItemIterator(BaseIter):
270 def __init__(self, weakdict):
271 self._next = weakdict.data.iteritems().next
273 def next(self):
274 while 1:
275 wr, value = self._next()
276 key = wr()
277 if key is not None:
278 return key, value
281 class WeakValuedValueIterator(BaseIter):
282 def __init__(self, weakdict):
283 self._next = weakdict.data.itervalues().next
285 def next(self):
286 while 1:
287 wr = self._next()
288 obj = wr()
289 if obj is not None:
290 return obj
293 class WeakValuedItemIterator(BaseIter):
294 def __init__(self, weakdict):
295 self._next = weakdict.data.iteritems().next
297 def next(self):
298 while 1:
299 key, wr = self._next()
300 value = wr()
301 if value is not None:
302 return key, value
305 # no longer needed
306 del UserDict