Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove classes from __subclasses__?

When inheriting from a class, the child class is accessible on the parent via the .__subclasses__() method.

class BaseClass:
    pass

class SubClass(BaseClass):
    pass

BaseClass.__subclasses__()
# [<class '__main__.SubClass'>]

However, deleting the child class doesn't seem to remove it from the parent.

del SubClass

BaseClass.__subclasses__()
# [<class '__main__.SubClass'>]
  • Where does __subclasses__ get its information from? And can I manipulate it?

Or

  • Is there a proper way to remove a class and have its parent lose reference to it (e.g. BaseClass.remove_subclass(SubClass)?
like image 978
alxwrd Avatar asked Oct 16 '22 13:10

alxwrd


1 Answers

The subclass contains references to itself internally, so it continues to exist until it is garbage collected. If you force a garbage collection cycle it will disappear from the __subclasses__():

import gc
gc.collect()

and then it has gone.

However make sure you have deleted all other references to the class before you force the garbage collection. For example, if you do it interactively and the last output was the subclass list there will still be a reference to the class in _.

class BaseClass:
    pass

class SubClass(BaseClass):
    pass

print(BaseClass.__subclasses__())
# [<class '__main__.SubClass'>]
del SubClass

import gc
gc.collect()
print(BaseClass.__subclasses__())
# []

Output with python 3.7 is:

[<class '__main__.SubClass'>]
[]

I should probably also add that while garbage collection works for this simple case you probably shouldn't depend on it in real life: it would be far too easy to accidentally keep a reference to the subclass somewhere in your code and then wonder why the class never goes away.

What you are trying to do here is keep a registry of subclasses so that the factory can return an object of the appropriate class. If you want to be able to add and remove classes from the registry then I think you have to be explicit. You could still use __subclasses__ to find candidate classes, but keep a flag on each class to show whether it is enabled. Then instead of just deleting the subclass set the flag to show the class is no longer in use and then (if you want) delete it.

like image 191
Duncan Avatar answered Oct 21 '22 04:10

Duncan