1 """Weak reference support for Python.
3 This module is an implementation of PEP 205:
5 http://python.sourceforge.net/peps/pep-0205.html
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.
14 from _weakref
import \
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
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
43 def __getitem__(self
, key
):
51 return "<WeakValueDictionary at %s>" % id(self
)
53 def __setitem__(self
, key
, value
):
54 def remove(o
, data
=self
.data
, key
=key
):
56 self
.data
[key
] = ref(value
, remove
)
59 new
= WeakValueDictionary()
60 for key
, wr
in self
.data
.items():
66 def get(self
, key
, default
=None):
74 # This should only happen
81 for key
, wr
in self
.data
.items():
88 return WeakValuedItemIterator(self
)
91 return self
.data
.iterkeys()
95 return WeakValuedValueIterator(self
)
99 key
, wr
= self
.data
.popitem()
104 def setdefault(self
, key
, default
):
108 def remove(o
, data
=self
.data
, key
=key
):
110 self
.data
[key
] = ref(default
, remove
)
115 def update(self
, dict):
117 for key
, o
in dict.items():
118 def remove(o
, data
=d
, key
=key
):
120 d
[key
] = ref(o
, remove
)
124 for wr
in self
.data
.values():
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
142 def __init__(self
, dict=None):
144 if dict is not None: self
.update(dict)
145 def remove(k
, data
=self
.data
):
147 self
._remove
= remove
149 def __delitem__(self
, key
):
150 for ref
in self
.data
.iterkeys():
156 def __getitem__(self
, key
):
157 return self
.data
[ref(key
)]
160 return "<WeakKeyDictionary at %s>" % id(self
)
162 def __setitem__(self
, key
, value
):
163 self
.data
[ref(key
, self
._remove
)] = value
166 new
= WeakKeyDictionary()
167 for key
, value
in self
.data
.items():
173 def get(self
, key
, default
=None):
174 return self
.data
.get(ref(key
),default
)
176 def has_key(self
, key
):
177 return self
.data
.has_key(ref(key
))
181 for key
, value
in self
.data
.items():
188 return WeakKeyedItemIterator(self
)
191 return WeakKeyedKeyIterator(self
)
194 def itervalues(self
):
195 return self
.data
.itervalues()
199 for wr
in self
.data
.keys():
207 key
, value
= self
.data
.popitem()
212 def setdefault(self
, key
, default
):
213 return self
.data
.setdefault(ref(key
, self
._remove
),default
)
215 def update(self
, dict):
217 for key
, value
in dict.items():
218 d
[ref(key
, self
._remove
)] = value
226 class WeakKeyedKeyIterator(BaseIter
):
227 def __init__(self
, weakdict
):
228 self
._next
= weakdict
.data
.iterkeys().next
238 class WeakKeyedItemIterator(BaseIter
):
239 def __init__(self
, weakdict
):
240 self
._next
= weakdict
.data
.iteritems().next
244 wr
, value
= self
._next
()
250 class WeakValuedValueIterator(BaseIter
):
251 def __init__(self
, weakdict
):
252 self
._next
= weakdict
.data
.itervalues().next
262 class WeakValuedItemIterator(BaseIter
):
263 def __init__(self
, weakdict
):
264 self
._next
= weakdict
.data
.iteritems().next
268 key
, wr
= self
._next
()
270 if value
is not None: