Is there a way to call a method on definition of a subclass in Python?

天涯浪子 提交于 2020-05-29 05:15:29

问题


The __init__ method defines what is done on creating an instance of a class. Can I do something equivalent when a subclass is created?

Let's say I have the abstract class Entity:

class Entity:
    def __onsubclasscreation__(cls):
        for var in cls.__annotations__:
            cls.__dict__[var] = property(lambda self:self.vars[var])

This would mean that whenever I define a new class inheriting from Entity, all annotated variables of that class would receive a getter:

class Train(Entity):
    wagons: int
    color: str

>>> t = Train()
>>> t.vars["wagons"] = 5
>>> t.wagons
5

I can't do this on instantiation because properties need to be defined in the class, and I can't do it in the superclass because I don't know which attributes will be needed. Is there any way to do something dynamically on subclass creation?


回答1:


You are describing the basic usage of __init_subclass__ hook (docs):

Whenever a class inherits from another class, __init_subclass__ is called on that class. This way, it is possible to write classes which change the behavior of subclasses.

>>> class A: 
...     def __init_subclass__(cls): 
...         print(f"init {cls}") 
...
>>> class B(A): 
...     pass 
...
init <class '__main__.B'>

See PEP 487 -- Simpler customisation of class creation for more information.

Note: This is a 3.6+ feature. In older Python versions, use the metaclass __new__ to achieve same:

>>> class MyMeta(type):
...     def __new__(meta, name, bases, class_dict):
...         print("MyMeta.__new__", meta, name, bases, class_dict)
...         return type.__new__(meta, name, bases, class_dict)
...
>>> class A(metaclass=MyMeta):
...     pass
...
MyMeta.__new__ <class '__main__.MyMeta'> A () {'__module__': '__main__', '__qualname__': 'A'}
>>> class B(A):
...     pass
...
MyMeta.__new__ <class '__main__.MyMeta'> B (<class '__main__.A'>,) {'__module__': '__main__', '__qualname__': 'B'}



回答2:


You might be able to just abstract this functionality out into another method and call that method from the superclass's constructor. If subclasses call the superclass's constructor (which they should) then that method will get executed when a subclass is instantiated.

class Entity:
    @classmethod
    def _onsubclasscreation(cls):
        for var in cls.__annotations__:
            cls.__dict__[var] = property(lambda self:self.vars[var])

    def __init__(self):
        ...
        self.__class__._onsubclasscreation()

And then, as long as subclasses don't overwrite the functionality of _onsubclasscreation(), the behavior should be as expected.



来源:https://stackoverflow.com/questions/57151233/is-there-a-way-to-call-a-method-on-definition-of-a-subclass-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!