When is the below python static classs variable garbage collected? I was expecting to see the message from the static variable foo destructor.
class Foo(object):
def __init__(self):
print "Foo init running"
def __del__(self):
print "Destructor Foo"
class Bar(object):
foo = Foo()
def __init__(self):
print "Bar init running"
def __del__(self):
print "Destructor Bar"
bar_obj = Bar()
The output is (Python 2.7):
Foo init running
Bar init running
Destructor Bar
I was expecting:
Foo init running
Bar init running
Destructor Foo
Destructor Bar
So we would expect the reference to the foo
object to be deleted when the Bar
class is deleted. And that is generally what happens. If you try
class Foo(object):
def __init__(self):
print("Foo init running")
def __del__(self):
print("Destructor Foo")
class Bar(object):
foo = Foo()
def __init__(self):
print("Bar init running")
def __del__(self):
print("Destructor Bar")
def f():
bar_obj = Bar()
f()
del Bar
I get
Foo init running
Bar init running
Destructor Bar
Destructor Foo
and you can see both destructors called in both Python 2.7 and Python 3.4. However, in Python 2.7, Bar
is not being properly destructed during program close down. As the docs say:
It is not guaranteed that del() methods are called for objects that still exist when the interpreter exits.
Why is Bar
not destructed during interpreter exit?
It seems likely that the class in Python 2.7 is not destructed because of circular references (see below). In Python 3.4 (after PEP 442) objects with circular references are reliably destructed (even if they have __del__
methods) and this may explain the change.
However, this does not completely explain the difference because although the class is in a reference cycle, the class itself does not have a destructor.
It seems that in Python 2 objects with circular references are not reliably destructed during interpreter exit, whereas they are in Python 3.4. I give some more information here.
Edit (more detail about circular references):
Classes contain cyclic references back to themselves, firstly via their dictionary:
MyClass.__dict__['__dict__'].__objclass__ == MyClass
and secondly via their MRO details:
MyClass in MyClass.__mro__
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With