__del__method not executing when involving circular reference

624 Views Asked by At

I find that custom __del__ method seems not to execute when circular referencing are involved.

Here is a sample code:

class DelClass():
        def __init__(self,a):
            self.prop = a 

        def __del__(self):
            print 'del'



if __name__ == "__main__":

    dc1 = DelClass(None)
    dc2 = DelClass(dc1)#dc2 referring to dc1
    dc1.prop = dc2#dc1 referring to dc2, thus creating circular reference
    del dc1#not executing the custom __del__ method

    dc = DelClass(1)
    del dc#executing the custom __del__ method

Why this happens?

Edit: Thanks to BrenBarn. I found the reason.

del something only decrements the reference count of something by 1.

__del__ will only execute when the reference count reaches 0.

Here is a test code:

import gc

class DelClass():
    def __init__(self,name,a):
        self.name = name
        self.prop = a

    def __del__(self):
        print '#####deleting',self.name

dc1 = DelClass("dc1",None)
dc2 = DelClass("dc2",dc1)#dc2 referring to dc1
dc1.prop = dc2#dc1 referring to dc2, thus creating circular reference
print "before deleting dc1,reference count:",len(gc.get_referrers(dc1))
del dc1#not executing the custom __del__ method
print "after deleting dc1, reference count:",len(gc.get_referrers(dc2.prop))
print "deleting the reference held by dc2"
del dc2.prop
print dc2

The output is:

before deleting dc1,reference count: 2
after deleting dc1, reference count: 1
deleting the reference held by dc2
#####deleting dc1
<__main__.DelClass instance at 0x9316dec>
#####deleting dc2

And another question appears:

why the last line(#####deleting dc2) in the output happens?

Some implicit del operation happens?

4

There are 4 best solutions below

0
On

Because the garbage collector has no way of knowing which can safely be deleted first.

0
On

Read the documentation for __del__ and for the garbage collector. __del__ doesn't do what you probably think it does, nor does del. __del__ is not necessarily called when you do a del, and may never be called in case of circular references. All del does is decrement the reference count by 1.

0
On

Read this link. I think this will help you.

del doesn't call __del__

del in the way you are using removes a local variable. __del__ is called when the object is destroyed. Python as a language makes no guarantees as to when it will destroy an object.

----Update Edit----

Answer to Some implicit del operation happens?

Read this link will help you

Python doesn't make any guarantees about when __del__ is called, or whether it is called at all. As it is, __del__ methods are unlikely to be called if the object is part of a reference cycle, because even if the cycle as a whole is cleaned up, Python has no way to decide where to break the cycle and in what order the __del__ methods (if any) should be called. Because of __del__'s rather quirky semantics (in order to call __del__ the refcount of the object is temporarily increased, and the __del__ method can prevent destruction of the object by storing the reference somewhere else) what happens in other implementations is a bit of a crapshoot. (I don't remember the exact details in current Jython, but it has changed a few times in the past.)

That said, in CPython, if __del__ is called, it's called as soon as the reference count drops to zero (since refcounting is the only way __del__ methods are called, and the only chance CPython has of calling __del__ is when the actual refcount is changed.)

0
On

This is not true anymore since python 3.4. See PEP-442.