Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When are python classes and class attributes garbage collected?

class Member(object):
    def __init__(self, identifier):
        self.identifier = identifier
        print "Member __init__", self.identifier

    def __del__(self):
        print "Member __del__", self.identifier
        with open("/home/might/" + self.identifier, "w") as outF:
            outF.write(self.identifier)

class WithMembers(object):
    def __init__(self):
        print "WithMembers __init__"
        print WithMembers.classMem
        self.instanceMem = Member("instance mem")

    def __del__(self):
        print "WithMembers __del__"

    classMem = Member("class mem")

if __name__ == "__main__":
    print "main"
    WithMembers()
    #del WithMembers.classMem       # "Member __del__ class mem" before "end"
    #del WithMembers                # "Member __del__ class mem" after "end"
    print "end"

The above code is in Hidden.py and running python Hidden.py produces the following output:

Member __init__ class mem
main
WithMembers __init__
<__main__.Member object at 0x935aeec>
Member __init__ instance mem
WithMembers __del__
Member __del__ instance mem
end

I don't see Member __del__ class mem in output or the class mem file unless I un-comment one of the del statements. Why is this? When are python classes and class attributes garbage collected?

like image 210
Might Avatar asked Sep 29 '22 18:09

Might


1 Answers

This was reported as a bug in http://bugs.python.org/issue1545463 fixed in 3.4 but not backported (I was running 2.7). This was also explained in http://code.activestate.com/lists/python-list/504216/ . See below for output in python 3.5.

Based on above, my understanding is that in 2.7 , new style class WithMembers is still around (not cleaned up by GC) when interpreter exits. As a result, classMem is not garbage collected because WithMembers still references it.

Notice new style classes have cyclic references to themselves from __mro__ and some built-in descriptors (http://bugs.python.org/issue17950). Even though module-level new-style classes are considered dead by GC after module cleanup, the GC call to clean them up after module cleanup is disabled because it caused too many other problems.

This doesn't cause memory leak because OS cleans up resources after interpreter exits.

class Member(object):
    def __init__(self, identifier):
        self.identifier = identifier
        print("Member __init__ " + self.identifier)

    def __del__(self):
        print("Member __del__ " + self.identifier)
        with open("/home/might/" + self.identifier, "w") as outF:
            outF.write(self.identifier)

class WithMembers(object):
    def __init__(self):
        print("WithMembers __init__")
        print(WithMembers.classMem)
        self.instanceMem = Member("instance mem")

    def __del__(self):
        print("WithMembers __del__")

    classMem = Member("class mem")

if __name__ == "__main__":
    print("main")
    WithMembers()
    print("end")

outputs the following when run with python3 Hidden.py:

Member __init__ class mem
main
WithMembers __init__
<__main__.Member object at 0xb6fc8e2c>
Member __init__ instance mem
WithMembers __del__
Member __del__ instance mem
end
Member __del__ class mem
Exception ignored in: <bound method Member.__del__ of <__main__.Member object at 0xb6fc8e2c>>
Traceback (most recent call last):
  File "class_member_gc.py", line 8, in __del__
NameError: name 'open' is not defined
like image 162
Might Avatar answered Oct 05 '22 07:10

Might