Merged release21-maint changes.
[python/dscho.git] / Lib / weakref.py
blob1d21e7988670538c8f771f975fbf71326f3848a8
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 ReferenceError, \
20 CallableProxyType, \
21 ProxyType, \
22 ReferenceType
24 ProxyTypes = (ProxyType, CallableProxyType)
26 __all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
27 "WeakKeyDictionary", "ReferenceType", "ProxyType",
28 "CallableProxyType", "ProxyTypes", "WeakValueDictionary"]
31 class WeakValueDictionary(UserDict.UserDict):
32 """Mapping class that references values weakly.
34 Entries in the dictionary will be discarded when no strong
35 reference to the value exists anymore
36 """
37 # We inherit the constructor without worrying about the input
38 # dictionary; since it uses our .update() method, we get the right
39 # checks (if the other dictionary is a WeakValueDictionary,
40 # objects are unwrapped on the way out, and we always wrap on the
41 # way in).
43 def __getitem__(self, key):
44 o = self.data[key]()
45 if o is None:
46 raise KeyError, key
47 else:
48 return o
50 def __repr__(self):
51 return "<WeakValueDictionary at %s>" % id(self)
53 def __setitem__(self, key, value):
54 def remove(o, data=self.data, key=key):
55 del data[key]
56 self.data[key] = ref(value, remove)
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 def remove(o, data=self.data, key=key):
109 del data[key]
110 self.data[key] = ref(default, remove)
111 return default
112 else:
113 return wr()
115 def update(self, dict):
116 d = self.data
117 for key, o in dict.items():
118 def remove(o, data=d, key=key):
119 del data[key]
120 d[key] = ref(o, remove)
122 def values(self):
123 L = []
124 for wr in self.data.values():
125 o = wr()
126 if o is not None:
127 L.append(o)
128 return L
131 class WeakKeyDictionary(UserDict.UserDict):
132 """ Mapping class that references keys weakly.
134 Entries in the dictionary will be discarded when there is no
135 longer a strong reference to the key. This can be used to
136 associate additional data with an object owned by other parts of
137 an application without adding attributes to those objects. This
138 can be especially useful with objects that override attribute
139 accesses.
142 def __init__(self, dict=None):
143 self.data = {}
144 if dict is not None: self.update(dict)
145 def remove(k, data=self.data):
146 del data[k]
147 self._remove = remove
149 def __getitem__(self, key):
150 return self.data[ref(key)]
152 def __repr__(self):
153 return "<WeakKeyDictionary at %s>" % id(self)
155 def __setitem__(self, key, value):
156 self.data[ref(key, self._remove)] = value
158 def copy(self):
159 new = WeakKeyDictionary()
160 for key, value in self.data.items():
161 o = key()
162 if o is not None:
163 new[o] = value
164 return new
166 def get(self, key, default=None):
167 return self.data.get(ref(key),default)
169 def has_key(self, key):
170 return self.data.has_key(ref(key))
172 def items(self):
173 L = []
174 for key, value in self.data.items():
175 o = key()
176 if o is not None:
177 L.append((o, value))
178 return L
180 def iteritems(self):
181 return WeakKeyedItemIterator(self)
183 def iterkeys(self):
184 return WeakKeyedKeyIterator(self)
185 __iter__ = iterkeys
187 def itervalues(self):
188 return self.data.itervalues()
190 def keys(self):
191 L = []
192 for wr in self.data.keys():
193 o = wr()
194 if o is not None:
195 L.append(o)
196 return L
198 def popitem(self):
199 while 1:
200 key, value = self.data.popitem()
201 o = key()
202 if o is not None:
203 return o, value
205 def setdefault(self, key, default):
206 return self.data.setdefault(ref(key, self._remove),default)
208 def update(self, dict):
209 d = self.data
210 for key, value in dict.items():
211 d[ref(key, self._remove)] = value
214 class BaseIter:
215 def __iter__(self):
216 return self
219 class WeakKeyedKeyIterator(BaseIter):
220 def __init__(self, weakdict):
221 self._next = weakdict.data.iterkeys().next
223 def next(self):
224 while 1:
225 wr = self._next()
226 obj = wr()
227 if obj is not None:
228 return obj
231 class WeakKeyedItemIterator(BaseIter):
232 def __init__(self, weakdict):
233 self._next = weakdict.data.iteritems().next
235 def next(self):
236 while 1:
237 wr, value = self._next()
238 key = wr()
239 if key is not None:
240 return key, value
243 class WeakValuedValueIterator(BaseIter):
244 def __init__(self, weakdict):
245 self._next = weakdict.data.itervalues().next
247 def next(self):
248 while 1:
249 wr = self._next()
250 obj = wr()
251 if obj is not None:
252 return obj
255 class WeakValuedItemIterator(BaseIter):
256 def __init__(self, weakdict):
257 self._next = weakdict.data.iteritems().next
259 def next(self):
260 while 1:
261 key, wr = self._next()
262 value = wr()
263 if value is not None:
264 return key, value
267 # no longer needed
268 del UserDict