Can someone explain this weakref behavior?

Peter Otten __peter__ at web.de
Fri Jun 11 13:53:28 EDT 2004


Michael Kent wrote:

> The Python 2.3.4 docs about weakref say:
> Not all objects can be weakly referenced; those objects which can
> include class instances, functions written in Python (but not in C),
> and methods (both bound and unbound).
> 
> 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)
> 
> It is acting as though a bound method is silently not allowed as the
> key in a WeakKeyDictionary.  Can someone set me straight?

You need a (strong) reference to the bound methods in order to keep them
from being garbage-collected (and therefore removed from the
WeakKeyDictionary) - not keeping alive the referenced keys is pretty much
the WeakKeyDictionary's raison d'être. A modified

    def test_01_simple(self):

        obj1 = someClass()
        obj2 = someClass()
        wkd = weakref.WeakKeyDictionary()
        m1 = obj1.aMethod
        m2 = obj2.aMethod

        wkd[obj1] = 1
        self.assertEqual(len(wkd), 1)
        wkd[m1] = 1
        self.assertEqual(len(wkd), 2)
        wkd[m2] = 1
        self.assertEqual(len(wkd), 3)

should complete without failure.

Peter




More information about the Python-list mailing list