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?
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'}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With