Reputation: 129
I have been playing around with Python objects in IDLE and observed that if a member variable of an object is changed, the memory isn't released! Here is an example:
import weakref
import gc
class subclass():
def __init__(self, data):
self.data=data
def __repr__(self):
return self.data.__str__()
class newclass():
def __init__(self,data):
self.data=subclass(data)
def test(self):
refs=weakref.ref(self.data)()
self.data=None
gc.collect()
print ("ref", refs)
a = newclass(data=3)
a.test()
print ("val", a.data)
The output of this code, I would expect to be:
ref None
val None
It turns out that the ref, however, is still a valid reference and the output is:
ref 3
val None
I would like to see that memory being released. I would like to understand how.
Upvotes: 0
Views: 88
Reputation: 160447
You've misunderstood something crucial, unfortunately. When you call the weakref
object returned from weakref.ref
you get back the original object. Try printing type(ref)
and see how <class '__main__.subclass'>
is returned. See the docs on weakref.ref
:
The original object can be retrieved by calling the reference object if the referent is still alive; if the referent is no longer alive, calling the reference object will cause
None
to be returned.
(Emphasis mine)
You called the reference object and got your class subclass
back; a reference to it therefore still exists in ref
not allowing it to get garbage-collected.
If you don't call it, on the other hand, you'll notice how the line print('ref', refs)
indicates that the reference is dead:
ref <weakref at 0x7f3028188a48; dead>
val None
i.e as the sole reference to your object and due to the fact it is weak, it got collected.
As an aside, if you want to be portable between Python 2 and 3 you'll want your classes to subclass from object
and not use empty parentheses ()
. If you don't care about portability, the parentheses can be dropped without change in semantics. :-)
Upvotes: 3