Self-deleting class in Python

Viewed 119

EDIT: Disclaimer - I don't mean deletion in the sense that applies to languages that aren't memory-managed (e.g. free in C++). Deletion here is to be understood as the fact that the superclass doesn't have the subclass as one of its subclasses anymore after its been deleted.

In Python, you can delete a class (yes I do mean a class, not an instance) by doing the following:

class Super:
    ...
    
class DeleteMe(Super):
    ...

print(Super.__subclasses__())
# [<class '__main__.DeleteMe'>]

del DeleteMe
import gc
gc.collect() # Force a collection

print(Super.__subclasses__())
# []

I am trying to emulate this behaviour but I want the DeleteMe class to be able to destroy itself. Here is what I've tried:

class Super:
    ...
    
class DeleteMe(Super):
    def self_delete(self):
        print(self.__class__)
        # <class '__main__.DeleteMe'>, this looks right
        del self.__class__ # this fails
        import gc
        gc.collect()

print(Super.__subclasses__())
# [<class '__main__.DeleteMe'>]

DeleteMe().self_delete()

It fails with the following traceback:

Traceback (most recent call last):
  File "/Users/rayan/Desktop/test.py", line 10, in <module>
    DeleteMe().self_delete()
  File "/Users/rayan/Desktop/test.py", line 4, in self_delete
    del self.__class__
TypeError: can't delete __class__ attribute

How can I achieve this self-destructing behaviour?

Note: not a duplicate of How to remove classes from __subclasses__?, that question covers the first case where the deletion happens outside of the class

1 Answers
del DestructMe

This is not deleting the class. This is deleting the name that happens to refer to the class. If there are no other references to the class (and that includes the name you just deleted, any module that's ever imported the class, any instances of the class, and any other places where the class might happen to be stored), then the garbage collector might delete the class when you gc.collect().

Now an instance always knows its own class, via the __class__ attribute. It makes little sense to delete self.__class__, because then what would we be left with? An instance with no class? What can we do with it? We can't call methods on it since those are defined on the class, and we can't do anything object-like on it since it's no longer an instance of object (a superclass of the class we just removed). So really we have a sort of silly looking dictionary that doesn't even do all of the dict things in Python. Hence, disallowed.

You cannot delete data in Python. That's the garbage collector's job. There is no Python equivalent of C's free or C++'s delete. del in Python deletes bindings or dictionary entries. It does not remove data; it removes pointers that happen to point to data.

Related