Is there a way to execute some code in Python when a class is extended by another one? More precisely, I would like to automatically keep a register of all the classes extending a base class. Therefore, I would like to write something like:
class Base:
subclasses = {}
@classmethod
def extending(cls, subclass):
cls.subclasses[subclass.__name__] = subclass
class Extend1(Base):
pass
class Extend2(Base):
pass
After this piece of code, I would expect Base.subclasses to contain links to the two extending classes.
Can you suggest a way to make this work? Or, maybe, provide an equivalent solution?
This is clearly an application for metaclasses. That is if you want to change the behavior of a classe C then you should change the class of C itself which is a metaclass, usually type
. Here is a stub of solution:
class Meta(type):
def __new__(cls, clsname, bases, dct):
res = type.__new__(cls, clsname, bases, dct)
for cls in bases:
if isinstance(cls, Meta):
try:
cls.extending(res)
except AttributeError:
pass
return res
I'm inheriting from type
to make a metaclass intercepting the creation of the class and storing the created class in the base _subclass
attribute. Then with
class Base(object):
__metaclass__ = Meta
subclasses = {}
@classmethod
def extending(cls, subclass):
cls.subclasses[subclass.__name__] = subclass
class Extend1(Base):
pass
class Extend2(Base):
pass
Then
>>> Base.subclasses
{'Extend1': __main__.Extend1, 'Extend2': __main__.Extend2}
A very important point: metaclass are inherited
(I think this is not the exactly the proper term here). Therefore Extend1
and Extend2
are also instances of Meta
:
>>> type(Extend1)
<class '__main__.Meta'>