blob: 32c11abfaca421d519f43152d1c91fac9c49aa6a [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
5http://python.sourceforge.net/peps/pep-0205.html
6"""
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
Fred Drake41deb1e2001-02-01 05:27:45 +000012import 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
Fred Drake9a9d2192001-04-10 19:11:23 +000026__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
Skip Montanaro40fc1602001-03-01 04:27:19 +000027 "WeakKeyDictionary", "ReferenceType", "ProxyType",
28 "CallableProxyType", "ProxyTypes", "WeakValueDictionary"]
Fred Drake41deb1e2001-02-01 05:27:45 +000029
Fred Drake41deb1e2001-02-01 05:27:45 +000030
Fred Drakebd7f8182001-04-19 16:26:06 +000031class 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 """
Fred Drake41deb1e2001-02-01 05:27:45 +000037 # We inherit the constructor without worrying about the input
38 # dictionary; since it uses our .update() method, we get the right
Fred Drake9d2c85d2001-03-01 03:06:03 +000039 # 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).
Fred Drake41deb1e2001-02-01 05:27:45 +000042
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):
Fred Drake9d2c85d2001-03-01 03:06:03 +000051 return "<WeakValueDictionary at %s>" % id(self)
Fred Drake41deb1e2001-02-01 05:27:45 +000052
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):
Fred Drake9d2c85d2001-03-01 03:06:03 +000059 new = WeakValueDictionary()
Fred Drakebd7f8182001-04-19 16:26:06 +000060 for key, wr in self.data.items():
61 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +000062 if o is not None:
63 new[key] = o
Fred Drake9d2c85d2001-03-01 03:06:03 +000064 return new
Fred Drake41deb1e2001-02-01 05:27:45 +000065
Fred Drake1d9e4b72001-04-16 17:34:48 +000066 def get(self, key, default=None):
Fred Drake41deb1e2001-02-01 05:27:45 +000067 try:
Fred Drakebd7f8182001-04-19 16:26:06 +000068 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +000069 except KeyError:
70 return default
71 else:
Fred Drakebd7f8182001-04-19 16:26:06 +000072 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +000073 if o is None:
74 # This should only happen
75 return default
76 else:
77 return o
78
79 def items(self):
Fred Drake312a5dc2001-02-02 15:13:24 +000080 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +000081 for key, wr in self.data.items():
82 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +000083 if o is not None:
Fred Drake312a5dc2001-02-02 15:13:24 +000084 L.append((key, o))
Fred Drake41deb1e2001-02-01 05:27:45 +000085 return L
86
87 def popitem(self):
88 while 1:
Fred Drakebd7f8182001-04-19 16:26:06 +000089 key, wr = self.data.popitem()
90 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +000091 if o is not None:
92 return key, o
93
94 def setdefault(self, key, default):
95 try:
Fred Drakebd7f8182001-04-19 16:26:06 +000096 wr = self.data[key]
Fred Drake41deb1e2001-02-01 05:27:45 +000097 except KeyError:
98 def remove(o, data=self.data, key=key):
99 del data[key]
Fred Drakebd7f8182001-04-19 16:26:06 +0000100 self.data[key] = ref(default, remove)
Fred Drake41deb1e2001-02-01 05:27:45 +0000101 return default
102 else:
Fred Drakebd7f8182001-04-19 16:26:06 +0000103 return wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000104
105 def update(self, dict):
106 d = self.data
Fred Drake41deb1e2001-02-01 05:27:45 +0000107 for key, o in dict.items():
108 def remove(o, data=d, key=key):
109 del data[key]
Fred Drakebd7f8182001-04-19 16:26:06 +0000110 d[key] = ref(o, remove)
Fred Drake41deb1e2001-02-01 05:27:45 +0000111
112 def values(self):
113 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000114 for wr in self.data.values():
115 o = wr()
Fred Drake41deb1e2001-02-01 05:27:45 +0000116 if o is not None:
117 L.append(o)
118 return L
119
120
Martin v. Löwis5e163332001-02-27 18:36:56 +0000121class WeakKeyDictionary(UserDict.UserDict):
Fred Drakebd7f8182001-04-19 16:26:06 +0000122 """ 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 """
Martin v. Löwis5e163332001-02-27 18:36:56 +0000131
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
Fred Drake9d2c85d2001-03-01 03:06:03 +0000154 return new
Martin v. Löwis5e163332001-02-27 18:36:56 +0000155
Fred Drake1d9e4b72001-04-16 17:34:48 +0000156 def get(self, key, default=None):
Martin v. Löwis5e163332001-02-27 18:36:56 +0000157 return self.data.get(ref(key),default)
158
Fred Drake1d9e4b72001-04-16 17:34:48 +0000159 def has_key(self, key):
160 return self.data.has_key(ref(key))
161
Martin v. Löwis5e163332001-02-27 18:36:56 +0000162 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
Fred Drake1d9e4b72001-04-16 17:34:48 +0000170 def keys(self):
171 L = []
Fred Drakebd7f8182001-04-19 16:26:06 +0000172 for wr in self.data.keys():
173 o = wr()
Fred Drake1d9e4b72001-04-16 17:34:48 +0000174 if o is not None:
175 L.append(o)
176 return L
177
Martin v. Löwis5e163332001-02-27 18:36:56 +0000178 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
Martin v. Löwis5e163332001-02-27 18:36:56 +0000190 for key, value in dict.items():
Fred Drakebd7f8182001-04-19 16:26:06 +0000191 d[ref(key, self._remove)] = value
192
Martin v. Löwis5e163332001-02-27 18:36:56 +0000193
Fred Drake41deb1e2001-02-01 05:27:45 +0000194# no longer needed
195del UserDict