问题
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