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