Home > other >  How to make python class objects dependent on another and delete the object when the parent is delet
How to make python class objects dependent on another and delete the object when the parent is delet

Time:04-25

I have two python classes A and B. I want class A to depend on class B. Also when class A is deleted class B should be deleted as well. Any help regarding this matter is appreciated.

I have tried the implement this by the following code.

class A:
    def __init__(self):
        self.newobj = B()
    def __del__(self):
        del self.newobj
        print('an object of class A was destroyed')

class B:
    def __init__(self):
         #do stuff
    def __del__(self):
        print('an object of class B was destroyed')

if __name__ == "__main__":

    
    obj1= A()
    obj2 = obj1.newobj

when the destructor is being called because of class A, the newobj is not deleted. If i try to delete obj2 inside the class A destructor, it would throw off an error saying obj2 was referenced before assignment.

CodePudding user response:

With normal references, it's impossible. Deletion of resources is done when we have zero references left - and you just made a reference in obj2 which you cannot access in a different scope (some people say python passes arguments "by assignment" - creates new reference to the object)

However, python provides weak references. Weak references do not count towards garbage collecting. https://docs.python.org/3/library/weakref.html

Notes:

  • garbage collector might still take time to collect the parent (in example below I force it to collect)
  • if someone gets a hold of a normal reference, the sub-object will stay alive
import weakref 

class A:
    def __init__(self):
        self.__newobj = B()  # use double underscore in name to strongly suggest it shouldn't be used directly
    @property
    def newobj(self):
        return weakref.ref(self.__newobj)

class B:
    def __init__(self):
        self.test = "test"

obj1 = A()
weak_obj2 = obj1.newobj

We access the object itself by calling the reference. Do not store this call in another variable as that will be a normal reference then.*

print(weak_obj2)  # <weakref at memoryaddresshere; to 'B' at anotheraddress>
print(weak_obj2())
print(weak_obj2().test)

Let's test it by deleting obj1 and forcing garbage collection

del obj1
import gc
gc.collect()

print(weak_obj2)  # <weakref at memoryaddresshere; dead>
print(weak_obj2())  # None

And as I mentioned, don't store the call as it's a normal reference and will keep the sub-object alive.

obj1 = A()
weak_obj2 = obj1.newobj
obj2 = weak_obj2()  # storing the call

del obj1
gc.collect()
print(weak_obj2)  # not dead

del obj2
gc.collect()
print(weak_obj2)  # dead
  • Related