I would like to understand how object deletion works on python. Here is a very simple bunch of code.
class A(object):
def __init__(self):
setattr(self, "test", self._test)
def _test(self):
print "Hello, World!"
def __del__(self):
print "I'm dying!"
class B(object):
def test(self):
print "Hello, World!"
def __del__(self):
print "I'm dying"
print "----------Test on A"
A().test()
print "----------Test on B"
B().test()
Pythonista would recognize that I’m running a python 2.x version. More specially, this code runs on a python 2.7.1 setup.
This code outputs the following:
----------Test on A
Hello, World!
----------Test on B
Hello, World!
I'm dying
Surprisingly, A object is not deleted. I can understand why, since the setattr statement in __init__ produces a circular reference. But this one seems to be easy to resolve.
Finally, this page, in python documentation (Supporting Cyclic Garbage Collection), show that it’s possible to deal with this kind of circular reference.
I would like to know:
- why I never go thru my
__del__method inAclass? - if my diagnosis about circular reference is good, why my
objectsubclass does not support cyclic garbage collection? - finally, how to deal with this kind of
setattrif I really want to go thru__del__?
Note: In A if the setattr points to another method of my module, there’s no problem.
Fact 1
Instance methods are normally stored on the class. The interpreter first looks them up in the instance
__dict__, which fails, and then looks on the class, which succeeds.When you dynamically set the instance method of
Ain__init__, you create a reference to it in the instance dictionary. This reference is circular, so the refcount will never go to zero and the reference counter will not cleanAup.Fact 2
The garbage collector is what Python uses to deal with circular references. Unfortunately, it can’t handle objects with
__del__methods, since in general it can’t determine a safe order to call them. Instead, it just puts all such objects ingc.garbage. You can then go look there to break cycles, so they can be freed. From the docsTherefore
Don’t make cyclic references on objects with
__del__methods if you want them to be garbage collected.