1

I would like to reliably call the __del__ method of an object immediately when it gets deleted. I am aware that this has been asked for python 2, but the documentation of python 3 claims that the __del__ method is called when the reference count reaches 0. However, this does not seem to be the case with my program

import time

class MyClass:
    object_list = []
    def __init__(self):
        MyClass.object_list.append(self)
        print("object initialized")
    def __del__(self):
        print("executing cleanup steps")
        MyClass.object_list.remove(self)

a = MyClass()
b = MyClass()
c = MyClass()
print(len(MyClass.object_list))
del b
time.sleep(1)
print("sleep finished")
print(len(MyClass.object_list))

Try it online

What I want to achieve is to remove b from the object_list immediately when it is destroyed and also make the variable b inaccessible. So simply calling b.__del__() is not enough, I would need to also render b inaccessible.

Note: running first b.__del__() and then del b will lead to complaints when exiting the python interpreter.

Interestingly enough, a very similar program seems to call b.__del__() immediately when del b is executed.

import time

class MyClass:
    counter = 0
    def __init__(self, value):
        self.value = value
        print("object initialized")
        MyClass.counter+=1
    def __del__(self):
        print("executing cleanup steps")
        MyClass.counter-=1

a = MyClass(5)
b = MyClass(6)
c = MyClass(7)
print(MyClass.counter)
del b
time.sleep(1)
print("sleep finished")
print(MyClass.counter)

Try it online

EDIT
@Pranav Hosangadi pointed out that there is still a reference to the object in the object_list. What a shameful oversight of mine. Now I came up with a workaround by calling first b.__del__() and then del b, but it is a two step process. I would like to have it in one step, if possible.

import time

class MyClass:
    object_list = []
    def __init__(self, value):
        self.value = value
        MyClass.object_list.append(self)
        print("object initialized")
    def __del__(self):
        print("executing cleanup steps")
        try:
            MyClass.object_list.remove(self)
        except:
            pass

a = MyClass(1)
b = MyClass(2)
c = MyClass(3)
print(len(MyClass.object_list))
b.__del__()
del b
time.sleep(1)
print("sleep finished")
print(len(MyClass.object_list))
laolux
  • 1,445
  • 1
  • 17
  • 28
  • 1
    _"the documentation of python 3 claims that the `__del__` method is called when the reference count reaches 0"_ `MyClass.object_list` still contains a reference to the object formerly known as `b`, so the `b.__del__` isn't called. In the second case, there is no such reference, so `b.__del__` is called immediately. – Pranav Hosangadi Dec 15 '22 at 03:58

0 Answers0