blob: 468f8f1029024b78ebdac2f543c5db78810f685d [file] [log] [blame]
Fred Drake41deb1e2001-02-01 05:27:45 +00001"""Weak reference support for Python.
2
3This module is an implementation of PEP 205:
4
Christian Heimes81ee3ef2008-05-04 22:42:01 +00005http://www.python.org/dev/peps/pep-0205/
Fred Drake41deb1e2001-02-01 05:27:45 +00006"""
7
Fred Drakebd7f8182001-04-19 16:26:06 +00008# 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
Andrew M. Kuchling33ad28b2004-08-31 11:38:12 +000012from _weakref import (
13 getweakrefcount,
14 getweakrefs,
15 ref,
16 proxy,
17 CallableProxyType,
18 ProxyType,
19 ReferenceType)
Fred Drake41deb1e2001-02-01 05:27:45 +000020
Antoine Pitrouc1baa602010-01-08 17:54:23 +000021from _weakrefset import WeakSet, _IterationGuard
Fred Drakee0292422001-10-05 21:54:09 +000022
Brett Cannon663fffa2009-03-25 23:31:22 +000023import collections # Import after _weakref to avoid circular import.
24
Fred Drake41deb1e2001-02-01 05:27:45 +000025ProxyTypes = (ProxyType, CallableProxyType)
26
Fred Drake9a9d2192001-04-10 19:11:23 +000027__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
Gregory P. Smith7d10c2b2008-08-18 03:41:46 +000028 "WeakKeyDictionary", "ReferenceType", "ProxyType",
Raymond Hettinger93fa6082008-02-05 00:20:01 +000029 "CallableProxyType", "ProxyTypes", "WeakValueDictionary",
30 "WeakSet"]
Fred Drake41deb1e2001-02-01 05:27:45 +000031
Fred Drake41deb1e2001-02-01 05:27:45 +000032
Raymond Hettinger7ac60952008-02-05 01:15:57 +000033class WeakValueDictionary(collections.MutableMapping):
Fred Drakebd7f8182001-04-19 16:26:06 +000034 """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 """
Fred Drake41deb1e2001-02-01 05:27:45 +000039 # We inherit the constructor without worrying about the input
40 # dictionary; since it uses our .update() method, we get the right
Fred Drake9d2c85d2001-03-01 03:06:03 +000041 # 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).
Fred Drake41deb1e2001-02-01 05:27:45 +000044
Fred Drake0a4dd392004-07-02 18:57:45 +000045 def __init__(self, *args, **kw):
Fred Drake0a4dd392004-07-02 18:57:45 +000046 def remove(wr, selfref=ref(self)):
47 self = selfref()
48 if self is not None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +000049 if self._iterating:
50 self._pending_removals.append(wr.key)
51 else:
52 del self.data[wr.key]
Fred Drake0a4dd392004-07-02 18:57:45 +000053 self._remove = remove
Antoine Pitrouc1baa602010-01-08 17:54:23 +000054 # A list of keys to be removed
55 self._pending_removals = []
56 self._iterating = set()
Raymond Hettinger7ac60952008-02-05 01:15:57 +000057 self.data = d = {}
Antoine Pitrouc06de472009-05-30 21:04:26 +000058 self.update(*args, **kw)
Fred Drake0a4dd392004-07-02 18:57:45 +000059
Antoine Pitrouc1baa602010-01-08 17:54:23 +000060 def _commit_removals(self):
61 l = self._pending_removals
62 d = self.data
63 # We shouldn't encounter any KeyError, because this method should
64 # always be called *before* mutating the dict.
65 while l:
66 del d[l.pop()]
67
Fred Drake41deb1e2001-02-01 05:27:45 +000068 def __getitem__(self, key):
Fred Drake4fd06e02001-08-03 04:11:27 +000069 o = self.data[key]()
Fred Drake41deb1e2001-02-01 05:27:45 +000070 if o is None:
Collin Winterce36ad82007-08-30 01:19:48 +000071 raise KeyError(key)
Fred Drake41deb1e2001-02-01 05:27:45 +000072 else:
73 return o
74
Raymond Hettinger7ac60952008-02-05 01:15:57 +000075 def __delitem__(self, key):
Antoine Pitrouc1baa602010-01-08 17:54:23 +000076 if self._pending_removals:
77 self._commit_removals()
Raymond Hettinger7ac60952008-02-05 01:15:57 +000078 del self.data[key]
79
80 def __len__(self):
81 return sum(wr() is not None for wr in self.data.values())
82
Raymond Hettinger61146792004-08-19 21:32:06 +000083 def __contains__(self, key):
84 try:
85 o = self.data[key]()
86 except KeyError:
87 return False
88 return o is not None
89
Fred Drake41deb1e2001-02-01 05:27:45 +000090 def __repr__(self):
Fred Drake9d2c85d2001-03-01 03:06:03 +000091 return "<WeakValueDictionary at %s>" % id(self)
Fred Drake41deb1e2001-02-01 05:27:45 +000092
93 def __setitem__(self, key, value):
Antoine Pitrouc1baa602010-01-08 17:54:23 +000094 if self._pending_removals:
95 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +000096 self.data[key] = KeyedRef(value, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +000097
98 def copy(self):
Fred Drake9d2c85d2001-03-01 03:06:03 +000099 new = WeakValueDictionary()
Fred Drakebd7f8182001-04-19 16:26:06 +0000100 for key, wr in self.data.items():
101 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000102 if o is not None:
103 new[key] = o
Fred Drake9d2c85d2001-03-01 03:06:03 +0000104 return new
Fred Drake41deb1e2001-02-01 05:27:45 +0000105
Antoine Pitrou6e610062009-05-15 17:04:50 +0000106 __copy__ = copy
107
108 def __deepcopy__(self, memo):
109 from copy import deepcopy
110 new = self.__class__()
111 for key, wr in self.data.items():
112 o = wr()
113 if o is not None:
114 new[deepcopy(key, memo)] = o
115 return new
116
Fred Drake1d9e4b72001-04-16 17:34:48 +0000117 def get(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +0000118 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000119 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000120 except KeyError:
121 return default
122 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000123 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000124 if o is None:
125 # This should only happen
126 return default
127 else:
128 return o
129
130 def items(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000131 with _IterationGuard(self):
132 for k, wr in self.data.items():
133 v = wr()
134 if v is not None:
135 yield k, v
Fred Drake101209d2001-05-02 05:43:09 +0000136
Barry Warsawecaab832008-09-04 01:42:51 +0000137 def keys(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000138 with _IterationGuard(self):
139 for k, wr in self.data.items():
140 if wr() is not None:
141 yield k
Raymond Hettinger61146792004-08-19 21:32:06 +0000142
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000143 __iter__ = keys
Fred Drake101209d2001-05-02 05:43:09 +0000144
Thomas Wouters477c8d52006-05-27 19:21:47 +0000145 def itervaluerefs(self):
146 """Return an iterator that yields the weak references to the values.
147
148 The references are not guaranteed to be 'live' at the time
149 they are used, so the result of calling the references needs
150 to be checked before being used. This can be used to avoid
151 creating references that will cause the garbage collector to
152 keep the values around longer than needed.
153
154 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000155 with _IterationGuard(self):
156 for wr in self.data.values():
157 yield wr
Thomas Wouters477c8d52006-05-27 19:21:47 +0000158
Barry Warsawecaab832008-09-04 01:42:51 +0000159 def values(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000160 with _IterationGuard(self):
161 for wr in self.data.values():
162 obj = wr()
163 if obj is not None:
164 yield obj
Fred Drake101209d2001-05-02 05:43:09 +0000165
Fred Drake41deb1e2001-02-01 05:27:45 +0000166 def popitem(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000167 if self._pending_removals:
168 self._commit_removals()
Georg Brandlbd87d082010-12-03 07:49:09 +0000169 while True:
Fred Drakebd7f8182001-04-19 16:26:06 +0000170 key, wr = self.data.popitem()
171 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000172 if o is not None:
173 return key, o
174
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000175 def pop(self, key, *args):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000176 if self._pending_removals:
177 self._commit_removals()
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000178 try:
179 o = self.data.pop(key)()
180 except KeyError:
181 if args:
182 return args[0]
183 raise
184 if o is None:
Collin Winterce36ad82007-08-30 01:19:48 +0000185 raise KeyError(key)
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000186 else:
187 return o
188
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000189 def setdefault(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +0000190 try:
Fred Drakebd7f8182001-04-19 16:26:06 +0000191 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +0000192 except KeyError:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000193 if self._pending_removals:
194 self._commit_removals()
Fred Drake0a4dd392004-07-02 18:57:45 +0000195 self.data[key] = KeyedRef(default, self._remove, key)
Fred Drake41deb1e2001-02-01 05:27:45 +0000196 return default
197 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000198 return wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000199
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000200 def update(self, dict=None, **kwargs):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000201 if self._pending_removals:
202 self._commit_removals()
Fred Drake41deb1e2001-02-01 05:27:45 +0000203 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000204 if dict is not None:
205 if not hasattr(dict, "items"):
206 dict = type({})(dict)
207 for key, o in dict.items():
Fred Drake0a4dd392004-07-02 18:57:45 +0000208 d[key] = KeyedRef(o, self._remove, key)
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000209 if len(kwargs):
210 self.update(kwargs)
Fred Drake41deb1e2001-02-01 05:27:45 +0000211
Thomas Wouters477c8d52006-05-27 19:21:47 +0000212 def valuerefs(self):
213 """Return a list of weak references to the values.
214
215 The references are not guaranteed to be 'live' at the time
216 they are used, so the result of calling the references needs
217 to be checked before being used. This can be used to avoid
218 creating references that will cause the garbage collector to
219 keep the values around longer than needed.
220
221 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000222 return list(self.data.values())
Thomas Wouters477c8d52006-05-27 19:21:47 +0000223
Fred Drake0a4dd392004-07-02 18:57:45 +0000224
225class KeyedRef(ref):
226 """Specialized reference that includes a key corresponding to the value.
227
228 This is used in the WeakValueDictionary to avoid having to create
229 a function object for each key stored in the mapping. A shared
230 callback object can use the 'key' attribute of a KeyedRef instead
231 of getting a reference to the key from an enclosing scope.
232
233 """
234
235 __slots__ = "key",
236
237 def __new__(type, ob, callback, key):
238 self = ref.__new__(type, ob, callback)
239 self.key = key
240 return self
241
242 def __init__(self, ob, callback, key):
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000243 super().__init__(ob, callback)
Fred Drake746fe0f2001-09-28 19:01:26 +0000244
Fred Drake41deb1e2001-02-01 05:27:45 +0000245
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000246class WeakKeyDictionary(collections.MutableMapping):
Fred Drakebd7f8182001-04-19 16:26:06 +0000247 """ Mapping class that references keys weakly.
248
249 Entries in the dictionary will be discarded when there is no
250 longer a strong reference to the key. This can be used to
251 associate additional data with an object owned by other parts of
252 an application without adding attributes to those objects. This
253 can be especially useful with objects that override attribute
254 accesses.
255 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000256
257 def __init__(self, dict=None):
258 self.data = {}
Fred Drake746fe0f2001-09-28 19:01:26 +0000259 def remove(k, selfref=ref(self)):
260 self = selfref()
261 if self is not None:
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000262 if self._iterating:
263 self._pending_removals.append(k)
264 else:
265 del self.data[k]
Martin v. Löwis5e163332001-02-27 18:36:56 +0000266 self._remove = remove
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000267 # A list of dead weakrefs (keys to be removed)
268 self._pending_removals = []
269 self._iterating = set()
270 if dict is not None:
271 self.update(dict)
272
273 def _commit_removals(self):
274 # NOTE: We don't need to call this method before mutating the dict,
275 # because a dead weakref never compares equal to a live weakref,
276 # even if they happened to refer to equal objects.
277 # However, it means keys may already have been removed.
278 l = self._pending_removals
279 d = self.data
280 while l:
281 try:
282 del d[l.pop()]
283 except KeyError:
284 pass
Martin v. Löwis5e163332001-02-27 18:36:56 +0000285
Fred Drakeb663a2c2001-09-06 14:51:01 +0000286 def __delitem__(self, key):
Tim Peters886128f2003-05-25 01:45:11 +0000287 del self.data[ref(key)]
Fred Drakeb663a2c2001-09-06 14:51:01 +0000288
Martin v. Löwis5e163332001-02-27 18:36:56 +0000289 def __getitem__(self, key):
290 return self.data[ref(key)]
291
Raymond Hettinger7ac60952008-02-05 01:15:57 +0000292 def __len__(self):
293 return len(self.data)
294
Martin v. Löwis5e163332001-02-27 18:36:56 +0000295 def __repr__(self):
296 return "<WeakKeyDictionary at %s>" % id(self)
297
298 def __setitem__(self, key, value):
299 self.data[ref(key, self._remove)] = value
300
301 def copy(self):
302 new = WeakKeyDictionary()
303 for key, value in self.data.items():
304 o = key()
305 if o is not None:
306 new[o] = value
Fred Drake9d2c85d2001-03-01 03:06:03 +0000307 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000308
Antoine Pitrou6e610062009-05-15 17:04:50 +0000309 __copy__ = copy
310
311 def __deepcopy__(self, memo):
312 from copy import deepcopy
313 new = self.__class__()
314 for key, value in self.data.items():
315 o = key()
316 if o is not None:
317 new[o] = deepcopy(value, memo)
318 return new
319
Fred Drake1d9e4b72001-04-16 17:34:48 +0000320 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000321 return self.data.get(ref(key),default)
322
Raymond Hettinger54f02222002-06-01 14:18:47 +0000323 def __contains__(self, key):
324 try:
325 wr = ref(key)
326 except TypeError:
Georg Brandlbd87d082010-12-03 07:49:09 +0000327 return False
Raymond Hettinger54f02222002-06-01 14:18:47 +0000328 return wr in self.data
Tim Petersc411dba2002-07-16 21:35:23 +0000329
Martin v. Löwis5e163332001-02-27 18:36:56 +0000330 def items(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000331 with _IterationGuard(self):
332 for wr, value in self.data.items():
333 key = wr()
334 if key is not None:
335 yield key, value
Thomas Wouters477c8d52006-05-27 19:21:47 +0000336
Barry Warsawecaab832008-09-04 01:42:51 +0000337 def keys(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000338 with _IterationGuard(self):
339 for wr in self.data:
340 obj = wr()
341 if obj is not None:
342 yield obj
Raymond Hettinger61146792004-08-19 21:32:06 +0000343
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000344 __iter__ = keys
Fred Drake101209d2001-05-02 05:43:09 +0000345
Barry Warsawecaab832008-09-04 01:42:51 +0000346 def values(self):
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000347 with _IterationGuard(self):
348 for wr, value in self.data.items():
349 if wr() is not None:
350 yield value
Fred Drake101209d2001-05-02 05:43:09 +0000351
Thomas Wouters477c8d52006-05-27 19:21:47 +0000352 def keyrefs(self):
353 """Return a list of weak references to the keys.
354
355 The references are not guaranteed to be 'live' at the time
356 they are used, so the result of calling the references needs
357 to be checked before being used. This can be used to avoid
358 creating references that will cause the garbage collector to
359 keep the keys around longer than needed.
360
361 """
Antoine Pitrouc1baa602010-01-08 17:54:23 +0000362 return list(self.data)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000363
Martin v. Löwis5e163332001-02-27 18:36:56 +0000364 def popitem(self):
Georg Brandlbd87d082010-12-03 07:49:09 +0000365 while True:
Martin v. Löwis5e163332001-02-27 18:36:56 +0000366 key, value = self.data.popitem()
367 o = key()
368 if o is not None:
369 return o, value
370
Raymond Hettinger2c2d3222003-03-09 07:05:43 +0000371 def pop(self, key, *args):
372 return self.data.pop(ref(key), *args)
373
Walter Dörwald80ce6dd2004-05-27 18:16:25 +0000374 def setdefault(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000375 return self.data.setdefault(ref(key, self._remove),default)
376
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000377 def update(self, dict=None, **kwargs):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000378 d = self.data
Raymond Hettinger31017ae2004-03-04 08:25:44 +0000379 if dict is not None:
380 if not hasattr(dict, "items"):
381 dict = type({})(dict)
382 for key, value in dict.items():
383 d[ref(key, self._remove)] = value
384 if len(kwargs):
385 self.update(kwargs)