Skip to content

Commit 017e68c

Browse files
committed
SF #1479988: add methods to allow access to weakrefs for the
weakref.WeakKeyDictionary and weakref.WeakValueDictionary
1 parent a6d01ce commit 017e68c

3 files changed

Lines changed: 125 additions & 0 deletions

File tree

Doc/lib/libweakref.tex

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,24 @@ \section{\module{weakref} ---
147147
to vanish "by magic" (as a side effect of garbage collection).}
148148
\end{classdesc}
149149

150+
\class{WeakKeyDictionary} objects have the following additional
151+
methods. These expose the internal references directly. The
152+
references are not guaranteed to be ``live'' at the time they are
153+
used, so the result of calling the references needs to be checked
154+
before being used. This can be used to avoid creating references that
155+
will cause the garbage collector to keep the keys around longer than
156+
needed.
157+
158+
\begin{methoddesc}{iterkeyrefs}{}
159+
Return an iterator that yields the weak references to the keys.
160+
\versionadded{2.5}
161+
\end{methoddesc}
162+
163+
\begin{methoddesc}{keyrefs}{}
164+
Return a list of weak references to the keys.
165+
\versionadded{2.5}
166+
\end{methoddesc}
167+
150168
\begin{classdesc}{WeakValueDictionary}{\optional{dict}}
151169
Mapping class that references values weakly. Entries in the
152170
dictionary will be discarded when no strong reference to the value
@@ -160,6 +178,21 @@ \section{\module{weakref} ---
160178
to vanish "by magic" (as a side effect of garbage collection).}
161179
\end{classdesc}
162180

181+
\class{WeakValueDictionary} objects have the following additional
182+
methods. These method have the same issues as the
183+
\method{iterkeyrefs()} and \method{keyrefs()} methods of
184+
\class{WeakKeyDictionary} objects.
185+
186+
\begin{methoddesc}{itervaluerefs}{}
187+
Return an iterator that yields the weak references to the values.
188+
\versionadded{2.5}
189+
\end{methoddesc}
190+
191+
\begin{methoddesc}{valuerefs}{}
192+
Return a list of weak references to the values.
193+
\versionadded{2.5}
194+
\end{methoddesc}
195+
163196
\begin{datadesc}{ReferenceType}
164197
The type object for weak references objects.
165198
\end{datadesc}

Lib/test/test_weakref.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,10 +769,54 @@ def test_weak_keyed_iters(self):
769769
dict, objects = self.make_weak_keyed_dict()
770770
self.check_iters(dict)
771771

772+
# Test keyrefs()
773+
refs = dict.keyrefs()
774+
self.assertEqual(len(refs), len(objects))
775+
objects2 = list(objects)
776+
for wr in refs:
777+
ob = wr()
778+
self.assert_(dict.has_key(ob))
779+
self.assert_(ob in dict)
780+
self.assertEqual(ob.arg, dict[ob])
781+
objects2.remove(ob)
782+
self.assertEqual(len(objects2), 0)
783+
784+
# Test iterkeyrefs()
785+
objects2 = list(objects)
786+
self.assertEqual(len(list(dict.iterkeyrefs())), len(objects))
787+
for wr in dict.iterkeyrefs():
788+
ob = wr()
789+
self.assert_(dict.has_key(ob))
790+
self.assert_(ob in dict)
791+
self.assertEqual(ob.arg, dict[ob])
792+
objects2.remove(ob)
793+
self.assertEqual(len(objects2), 0)
794+
772795
def test_weak_valued_iters(self):
773796
dict, objects = self.make_weak_valued_dict()
774797
self.check_iters(dict)
775798

799+
# Test valuerefs()
800+
refs = dict.valuerefs()
801+
self.assertEqual(len(refs), len(objects))
802+
objects2 = list(objects)
803+
for wr in refs:
804+
ob = wr()
805+
self.assertEqual(ob, dict[ob.arg])
806+
self.assertEqual(ob.arg, dict[ob.arg].arg)
807+
objects2.remove(ob)
808+
self.assertEqual(len(objects2), 0)
809+
810+
# Test itervaluerefs()
811+
objects2 = list(objects)
812+
self.assertEqual(len(list(dict.itervaluerefs())), len(objects))
813+
for wr in dict.itervaluerefs():
814+
ob = wr()
815+
self.assertEqual(ob, dict[ob.arg])
816+
self.assertEqual(ob.arg, dict[ob.arg].arg)
817+
objects2.remove(ob)
818+
self.assertEqual(len(objects2), 0)
819+
776820
def check_iters(self, dict):
777821
# item iterator:
778822
items = dict.items()

Lib/weakref.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,18 @@ def iterkeys(self):
118118
def __iter__(self):
119119
return self.data.iterkeys()
120120

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+
121133
def itervalues(self):
122134
for wr in self.data.itervalues():
123135
obj = wr()
@@ -162,6 +174,18 @@ def update(self, dict=None, **kwargs):
162174
if len(kwargs):
163175
self.update(kwargs)
164176

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+
165189
def values(self):
166190
L = []
167191
for wr in self.data.values():
@@ -263,6 +287,18 @@ def iteritems(self):
263287
if key is not None:
264288
yield key, value
265289

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+
266302
def iterkeys(self):
267303
for wr in self.data.iterkeys():
268304
obj = wr()
@@ -275,6 +311,18 @@ def __iter__(self):
275311
def itervalues(self):
276312
return self.data.itervalues()
277313

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+
278326
def keys(self):
279327
L = []
280328
for wr in self.data.keys():

0 commit comments

Comments
 (0)