문제

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'>

다른 팁

actually, if you're only interested in subclasses, python can give you that automatically. all new style classes have a __subclasses__() method which returns all of that classes' direct descendants.

>>> class Base(object):
...     pass
...
>>> class Child(Base):
...     pass
...
>>> Base.__subclasses__()
[<class '__main__.Child'>]
>>>
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top