weakref.py revision bd7f818c508248e12f88e51198cb5e9b861dacbf
1"""Weak reference support for Python.
2
3This module is an implementation of PEP 205:
4
5http://python.sourceforge.net/peps/pep-0205.html
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     ReferenceError, \
20     CallableProxyType, \
21     ProxyType, \
22     ReferenceType
23
24ProxyTypes = (ProxyType, CallableProxyType)
25
26__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
27           "WeakKeyDictionary", "ReferenceType", "ProxyType",
28           "CallableProxyType", "ProxyTypes", "WeakValueDictionary"]
29
30
31class WeakValueDictionary(UserDict.UserDict):
32    """Mapping class that references values weakly.
33
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).
42
43    def __getitem__(self, key):
44        o = self.data.get(key)()
45        if o is None:
46            raise KeyError, key
47        else:
48            return o
49
50    def __repr__(self):
51        return "<WeakValueDictionary at %s>" % id(self)
52
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)
57
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
65
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
78
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
86
87    def popitem(self):
88        while 1:
89            key, wr = self.data.popitem()
90            o = wr()
91            if o is not None:
92                return key, o
93
94    def setdefault(self, key, default):
95        try:
96            wr = self.data[key]
97        except KeyError:
98            def remove(o, data=self.data, key=key):
99                del data[key]
100            self.data[key] = ref(default, remove)
101            return default
102        else:
103            return wr()
104
105    def update(self, dict):
106        d = self.data
107        for key, o in dict.items():
108            def remove(o, data=d, key=key):
109                del data[key]
110            d[key] = ref(o, remove)
111
112    def values(self):
113        L = []
114        for wr in self.data.values():
115            o = wr()
116            if o is not None:
117                L.append(o)
118        return L
119
120
121class WeakKeyDictionary(UserDict.UserDict):
122    """ Mapping class that references keys weakly.
123
124    Entries in the dictionary will be discarded when there is no
125    longer a strong reference to the key. This can be used to
126    associate additional data with an object owned by other parts of
127    an application without adding attributes to those objects. This
128    can be especially useful with objects that override attribute
129    accesses.
130    """
131
132    def __init__(self, dict=None):
133        self.data = {}
134        if dict is not None: self.update(dict)
135        def remove(k, data=self.data):
136            del data[k]
137        self._remove = remove
138
139    def __getitem__(self, key):
140        return self.data[ref(key)]
141
142    def __repr__(self):
143        return "<WeakKeyDictionary at %s>" % id(self)
144
145    def __setitem__(self, key, value):
146        self.data[ref(key, self._remove)] = value
147
148    def copy(self):
149        new = WeakKeyDictionary()
150        for key, value in self.data.items():
151            o = key()
152            if o is not None:
153                new[o] = value
154        return new
155
156    def get(self, key, default=None):
157        return self.data.get(ref(key),default)
158
159    def has_key(self, key):
160        return self.data.has_key(ref(key))
161
162    def items(self):
163        L = []
164        for key, value in self.data.items():
165            o = key()
166            if o is not None:
167                L.append((o, value))
168        return L
169
170    def keys(self):
171        L = []
172        for wr in self.data.keys():
173            o = wr()
174            if o is not None:
175                L.append(o)
176        return L
177
178    def popitem(self):
179        while 1:
180            key, value = self.data.popitem()
181            o = key()
182            if o is not None:
183                return o, value
184
185    def setdefault(self, key, default):
186        return self.data.setdefault(ref(key, self._remove),default)
187
188    def update(self, dict):
189        d = self.data
190        for key, value in dict.items():
191            d[ref(key, self._remove)] = value
192
193
194# no longer needed
195del UserDict
196