Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python static variable deallocation

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
like image 620
A.P. Avatar asked Oct 09 '15 08:10

A.P.


1 Answers

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__
like image 89
strubbly Avatar answered Oct 19 '22 19:10

strubbly