PageRenderTime 1203ms CodeModel.GetById 815ms app.highlight 95ms RepoModel.GetById 207ms app.codeStats 0ms

/Lib/weakref.py

http://unladen-swallow.googlecode.com/
Python | 355 lines | 311 code | 22 blank | 22 comment | 18 complexity | 35c7f84f1337f68075edb6673ce04d82 MD5 | raw file
  1"""Weak reference support for Python.
  2
  3This module is an implementation of PEP 205:
  4
  5http://www.python.org/dev/peps/pep-0205/
  6"""
  7
  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.
 11
 12import UserDict
 13
 14from _weakref import (
 15     getweakrefcount,
 16     getweakrefs,
 17     ref,
 18     proxy,
 19     CallableProxyType,
 20     ProxyType,
 21     ReferenceType)
 22
 23from exceptions import ReferenceError
 24
 25
 26ProxyTypes = (ProxyType, CallableProxyType)
 27
 28__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
 29           "WeakKeyDictionary", "ReferenceError", "ReferenceType", "ProxyType",
 30           "CallableProxyType", "ProxyTypes", "WeakValueDictionary"]
 31
 32
 33class WeakValueDictionary(UserDict.UserDict):
 34    """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    """
 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).
 44
 45    def __init__(self, *args, **kw):
 46        def remove(wr, selfref=ref(self)):
 47            self = selfref()
 48            if self is not None:
 49                del self.data[wr.key]
 50        self._remove = remove
 51        UserDict.UserDict.__init__(self, *args, **kw)
 52
 53    def __getitem__(self, key):
 54        o = self.data[key]()
 55        if o is None:
 56            raise KeyError, key
 57        else:
 58            return o
 59
 60    def __contains__(self, key):
 61        try:
 62            o = self.data[key]()
 63        except KeyError:
 64            return False
 65        return o is not None
 66
 67    def has_key(self, key):
 68        try:
 69            o = self.data[key]()
 70        except KeyError:
 71            return False
 72        return o is not None
 73
 74    def __repr__(self):
 75        return "<WeakValueDictionary at %s>" % id(self)
 76
 77    def __setitem__(self, key, value):
 78        self.data[key] = KeyedRef(value, self._remove, key)
 79
 80    def copy(self):
 81        new = WeakValueDictionary()
 82        for key, wr in self.data.items():
 83            o = wr()
 84            if o is not None:
 85                new[key] = o
 86        return new
 87
 88    def get(self, key, default=None):
 89        try:
 90            wr = self.data[key]
 91        except KeyError:
 92            return default
 93        else:
 94            o = wr()
 95            if o is None:
 96                # This should only happen
 97                return default
 98            else:
 99                return o
100
101    def items(self):
102        L = []
103        for key, wr in self.data.items():
104            o = wr()
105            if o is not None:
106                L.append((key, o))
107        return L
108
109    def iteritems(self):
110        for wr in self.data.itervalues():
111            value = wr()
112            if value is not None:
113                yield wr.key, value
114
115    def iterkeys(self):
116        return self.data.iterkeys()
117
118    def __iter__(self):
119        return self.data.iterkeys()
120
121    def itervaluerefs(self):
122        """Return an iterator that yields the weak references to the values.
123
124        The references are not guaranteed to be 'live' at the time
125        they are used, so the result of calling the references needs
126        to be checked before being used.  This can be used to avoid
127        creating references that will cause the garbage collector to
128        keep the values around longer than needed.
129
130        """
131        return self.data.itervalues()
132
133    def itervalues(self):
134        for wr in self.data.itervalues():
135            obj = wr()
136            if obj is not None:
137                yield obj
138
139    def popitem(self):
140        while 1:
141            key, wr = self.data.popitem()
142            o = wr()
143            if o is not None:
144                return key, o
145
146    def pop(self, key, *args):
147        try:
148            o = self.data.pop(key)()
149        except KeyError:
150            if args:
151                return args[0]
152            raise
153        if o is None:
154            raise KeyError, key
155        else:
156            return o
157
158    def setdefault(self, key, default=None):
159        try:
160            wr = self.data[key]
161        except KeyError:
162            self.data[key] = KeyedRef(default, self._remove, key)
163            return default
164        else:
165            return wr()
166
167    def update(self, dict=None, **kwargs):
168        d = self.data
169        if dict is not None:
170            if not hasattr(dict, "items"):
171                dict = type({})(dict)
172            for key, o in dict.items():
173                d[key] = KeyedRef(o, self._remove, key)
174        if len(kwargs):
175            self.update(kwargs)
176
177    def valuerefs(self):
178        """Return a list of weak references to the values.
179
180        The references are not guaranteed to be 'live' at the time
181        they are used, so the result of calling the references needs
182        to be checked before being used.  This can be used to avoid
183        creating references that will cause the garbage collector to
184        keep the values around longer than needed.
185
186        """
187        return self.data.values()
188
189    def values(self):
190        L = []
191        for wr in self.data.values():
192            o = wr()
193            if o is not None:
194                L.append(o)
195        return L
196
197
198class KeyedRef(ref):
199    """Specialized reference that includes a key corresponding to the value.
200
201    This is used in the WeakValueDictionary to avoid having to create
202    a function object for each key stored in the mapping.  A shared
203    callback object can use the 'key' attribute of a KeyedRef instead
204    of getting a reference to the key from an enclosing scope.
205
206    """
207
208    __slots__ = "key",
209
210    def __new__(type, ob, callback, key):
211        self = ref.__new__(type, ob, callback)
212        self.key = key
213        return self
214
215    def __init__(self, ob, callback, key):
216        super(KeyedRef,  self).__init__(ob, callback)
217
218
219class WeakKeyDictionary(UserDict.UserDict):
220    """ Mapping class that references keys weakly.
221
222    Entries in the dictionary will be discarded when there is no
223    longer a strong reference to the key. This can be used to
224    associate additional data with an object owned by other parts of
225    an application without adding attributes to those objects. This
226    can be especially useful with objects that override attribute
227    accesses.
228    """
229
230    def __init__(self, dict=None):
231        self.data = {}
232        def remove(k, selfref=ref(self)):
233            self = selfref()
234            if self is not None:
235                del self.data[k]
236        self._remove = remove
237        if dict is not None: self.update(dict)
238
239    def __delitem__(self, key):
240        del self.data[ref(key)]
241
242    def __getitem__(self, key):
243        return self.data[ref(key)]
244
245    def __repr__(self):
246        return "<WeakKeyDictionary at %s>" % id(self)
247
248    def __setitem__(self, key, value):
249        self.data[ref(key, self._remove)] = value
250
251    def copy(self):
252        new = WeakKeyDictionary()
253        for key, value in self.data.items():
254            o = key()
255            if o is not None:
256                new[o] = value
257        return new
258
259    def get(self, key, default=None):
260        return self.data.get(ref(key),default)
261
262    def has_key(self, key):
263        try:
264            wr = ref(key)
265        except TypeError:
266            return 0
267        return wr in self.data
268
269    def __contains__(self, key):
270        try:
271            wr = ref(key)
272        except TypeError:
273            return 0
274        return wr in self.data
275
276    def items(self):
277        L = []
278        for key, value in self.data.items():
279            o = key()
280            if o is not None:
281                L.append((o, value))
282        return L
283
284    def iteritems(self):
285        for wr, value in self.data.iteritems():
286            key = wr()
287            if key is not None:
288                yield key, value
289
290    def iterkeyrefs(self):
291        """Return an iterator that yields the weak references to the keys.
292
293        The references are not guaranteed to be 'live' at the time
294        they are used, so the result of calling the references needs
295        to be checked before being used.  This can be used to avoid
296        creating references that will cause the garbage collector to
297        keep the keys around longer than needed.
298
299        """
300        return self.data.iterkeys()
301
302    def iterkeys(self):
303        for wr in self.data.iterkeys():
304            obj = wr()
305            if obj is not None:
306                yield obj
307
308    def __iter__(self):
309        return self.iterkeys()
310
311    def itervalues(self):
312        return self.data.itervalues()
313
314    def keyrefs(self):
315        """Return a list of weak references to the keys.
316
317        The references are not guaranteed to be 'live' at the time
318        they are used, so the result of calling the references needs
319        to be checked before being used.  This can be used to avoid
320        creating references that will cause the garbage collector to
321        keep the keys around longer than needed.
322
323        """
324        return self.data.keys()
325
326    def keys(self):
327        L = []
328        for wr in self.data.keys():
329            o = wr()
330            if o is not None:
331                L.append(o)
332        return L
333
334    def popitem(self):
335        while 1:
336            key, value = self.data.popitem()
337            o = key()
338            if o is not None:
339                return o, value
340
341    def pop(self, key, *args):
342        return self.data.pop(ref(key), *args)
343
344    def setdefault(self, key, default=None):
345        return self.data.setdefault(ref(key, self._remove),default)
346
347    def update(self, dict=None, **kwargs):
348        d = self.data
349        if dict is not None:
350            if not hasattr(dict, "items"):
351                dict = type({})(dict)
352            for key, value in dict.items():
353                d[ref(key, self._remove)] = value
354        if len(kwargs):
355            self.update(kwargs)