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?
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
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