This commit was manufactured by cvs2svn to create tag 'r221c2'.
[python/dscho.git] / Lib / weakref.py
blob967458d989dc115e68756037f711b7e223a63110
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 setdefault(self, key, default):
105 try:
106 wr = self.data[key]
107 except KeyError:
108 self.data[key] = ref(default, self.__makeremove(key))
109 return default
110 else:
111 return wr()
113 def update(self, dict):
114 d = self.data
115 for key, o in dict.items():
116 d[key] = ref(o, self.__makeremove(key))
118 def values(self):
119 L = []
120 for wr in self.data.values():
121 o = wr()
122 if o is not None:
123 L.append(o)
124 return L
126 def __makeremove(self, key):
127 def remove(o, selfref=ref(self), key=key):
128 self = selfref()
129 if self is not None:
130 del self.data[key]
131 return remove
134 class WeakKeyDictionary(UserDict.UserDict):
135 """ Mapping class that references keys weakly.
137 Entries in the dictionary will be discarded when there is no
138 longer a strong reference to the key. This can be used to
139 associate additional data with an object owned by other parts of
140 an application without adding attributes to those objects. This
141 can be especially useful with objects that override attribute
142 accesses.
145 def __init__(self, dict=None):
146 self.data = {}
147 if dict is not None: self.update(dict)
148 def remove(k, selfref=ref(self)):
149 self = selfref()
150 if self is not None:
151 del self.data[k]
152 self._remove = remove
154 def __delitem__(self, key):
155 for ref in self.data.iterkeys():
156 o = ref()
157 if o == key:
158 del self.data[ref]
159 return
161 def __getitem__(self, key):
162 return self.data[ref(key)]
164 def __repr__(self):
165 return "<WeakKeyDictionary at %s>" % id(self)
167 def __setitem__(self, key, value):
168 self.data[ref(key, self._remove)] = value
170 def copy(self):
171 new = WeakKeyDictionary()
172 for key, value in self.data.items():
173 o = key()
174 if o is not None:
175 new[o] = value
176 return new
178 def get(self, key, default=None):
179 return self.data.get(ref(key),default)
181 def has_key(self, key):
182 try:
183 wr = ref(key)
184 except TypeError:
185 return 0
186 return self.data.has_key(wr)
188 def items(self):
189 L = []
190 for key, value in self.data.items():
191 o = key()
192 if o is not None:
193 L.append((o, value))
194 return L
196 def iteritems(self):
197 return WeakKeyedItemIterator(self)
199 def iterkeys(self):
200 return WeakKeyedKeyIterator(self)
201 __iter__ = iterkeys
203 def itervalues(self):
204 return self.data.itervalues()
206 def keys(self):
207 L = []
208 for wr in self.data.keys():
209 o = wr()
210 if o is not None:
211 L.append(o)
212 return L
214 def popitem(self):
215 while 1:
216 key, value = self.data.popitem()
217 o = key()
218 if o is not None:
219 return o, value
221 def setdefault(self, key, default):
222 return self.data.setdefault(ref(key, self._remove),default)
224 def update(self, dict):
225 d = self.data
226 for key, value in dict.items():
227 d[ref(key, self._remove)] = value
230 class BaseIter:
231 def __iter__(self):
232 return self
235 class WeakKeyedKeyIterator(BaseIter):
236 def __init__(self, weakdict):
237 self._next = weakdict.data.iterkeys().next
239 def next(self):
240 while 1:
241 wr = self._next()
242 obj = wr()
243 if obj is not None:
244 return obj
247 class WeakKeyedItemIterator(BaseIter):
248 def __init__(self, weakdict):
249 self._next = weakdict.data.iteritems().next
251 def next(self):
252 while 1:
253 wr, value = self._next()
254 key = wr()
255 if key is not None:
256 return key, value
259 class WeakValuedValueIterator(BaseIter):
260 def __init__(self, weakdict):
261 self._next = weakdict.data.itervalues().next
263 def next(self):
264 while 1:
265 wr = self._next()
266 obj = wr()
267 if obj is not None:
268 return obj
271 class WeakValuedItemIterator(BaseIter):
272 def __init__(self, weakdict):
273 self._next = weakdict.data.iteritems().next
275 def next(self):
276 while 1:
277 key, wr = self._next()
278 value = wr()
279 if value is not None:
280 return key, value
283 # no longer needed
284 del UserDict