Can someone explain this weakref behavior?

Tim Peters tim.one at comcast.net
Fri Jun 11 13:56:19 EDT 2004


[Michael Kent]
...
> I've been unable to get using a bound method as the key in a
> WeakKeyDictionary to work.  Using a class instance object works fine as a
> key, using a method of that same instance object does not. Here's some
> code, in a file named test_weakref.py:
>
> #! /usr/bin/env python
>
> import unittest import weakref
>
> class someClass(object):
>     def aMethod(self):
>         print "Hi!"
>
> class TestCase_01_weakref(unittest.TestCase):
>
>     def test_01_simple(self):
>
>         obj1 = someClass()
>         obj2 = someClass()
>         wkd = weakref.WeakKeyDictionary()
>
>         wkd[obj1] = 1
>         self.assertEqual(len(wkd), 1)
>
>         wkd[obj1.aMethod] = 1
>         self.assertEqual(len(wkd), 2)
>
>         wkd[obj2.aMethod] = 1
>         self.assertEqual(len(wkd), 3)
>
>
> if __name__ == "__main__":
>     unittest.main()
>
> And here's the output:
>
> ./test_weakref.py F
> ======================================================================
> FAIL: test_01_simple (__main__.TestCase_01_weakref)
> ----------------------------------------------------------------------
> Traceback (most recent call last):
>   File "./test_weakref.py", line 22, in test_01_simple
>     self.assertEqual(len(wkd), 2)
>   File "/usr/local/lib/python2.3/unittest.py", line 302, in
> failUnlessEqual
>     raise self.failureException, \
> AssertionError: 1 != 2
>
> ----------------------------------------------------------------------
> Ran 1 test in 0.001s
>
> FAILED (failures=1)

The bound methods you create become unreachable (via any strong reference)
the instant they're added to the weak dict, so they vanish from the weak
dict immediately after being added.  That's what a weak dict is supposed to
do.

One way to get the test to pass is to replace the tail end with:

        temp1 = obj1.aMethod
        wkd[temp1] = 1
        self.assertEqual(len(wkd), 2)

        temp2 = obj2.aMethod
        wkd[temp2] = 1
        self.assertEqual(len(wkd), 3)

That keeps the bound methods reachable via strong references for the
duration of the test.

After that, you could add:

        del temp1, temp2
        self.assertEqual(len(wkd), 1)

That will pass under CPython today, but there's no general guarantee about
exactly when a weak dict will notice that keys (or values) have become
unreachable by strong references.






More information about the Python-list mailing list