Search code examples
ooppython-3.xreferenceweak-references

Strange deletion behavior after removing last reference


I have a strange problem while trying to delete the last reference of an object.

The code is:

import sys
import weakref

class Ref:

    def __init__(self, name):
        self.name = name
        self.ref = []

    def reference(self, obj):
        name = obj.name
        self.ref.append(
            weakref.ref(obj, lambda wref: print('{!r} is dead.'.format(name))))


a = Ref('a')
b = Ref('b')
c = Ref('c')
d = Ref('d')

a.reference(b)
b.reference(c)
c.reference(d)
d.reference(a)

print('reference count before killed:', sys.getrefcount(d.ref[0]()))
del a
print('reference count after killed:', sys.getrefcount(d.ref[0]()))

And the output is this:

reference count before killed: 2
'a' is dead.
reference count after killed: 1547
'd' is dead.
'c' is dead.

But sometimes (it is totally random) I got only 'd' is dead. or 'c' is dead. (but never 'b' is dead.), or none of these messages at all.

So my first question is: What is this weird reference count 1547? And where does it come from?

And the second is: Why killing instance a creates this random "killing other instances" effect?


Solution

  • After a is GC'd, d.ref[0]() produces None. That's why you're getting a refcount of 1547 after deleting a; after all, you couldn't ask for the refcount of a collected object, could you?

    The weird deletion of c and d is because Python doesn't guarantee whether objects alive when the interpreter exits will go through the normal destruction process. b, c, and d are all alive at the end of your script. Sometimes, they'll get GC'd normally, and the weakref callbacks will run. Sometimes, that doesn't happen. Python makes no promises here.