Today I learned how to use the dunder method __init_subclass__
to be notified when a class is subclassed.
__init_subclass__
The dunder method __init_subclass__
is a class method that Python runs when a subclass of that class is instantiated.
The snippet below sums it all:
class Parent:
def __init_subclass__(cls):
print(f"Subclass {cls} was created.")
class A(Parent):
pass
class B(A):
pass
"""
Output:
Subclass <class '__main__.A'> was created.
Subclass <class '__main__.B'> was created.
"""
The code above shows that when subclasses are created (even if they are not direct subclasses, like the case of B
) the class method Parent.__init_subclass__
is called.
The class method __init_subclass__
will also receive the keyword arguments that you specify on class definition.
The snippet below shows this:
class Parent:
def __init_subclass__(cls, **kwargs):
print(f"Subclass {cls.__name__} created with {kwargs}")
class A(Parent, kwarg1=73, kwarg2=True):
pass
# Output: Subclass A created with {'kwarg1': 73, 'kwarg2': True}
__init_subclass__
The point of the dunder method __init_subclass__
is that a parent class can modify its child classes when they are being created, thus enabling metaprogramming.
For example, I needed to use __init_subclass__
in Textual to make sure that all subclasses of a particular class, named Widget
, had a name that starts with an upper case letter or with an underscore _
.
You can check the Textual codebase for the full context, but this was essentially what I implemented:
class BadWidgetName(Exception):
"""Raised when widget names do not satisfy the required restrictions."""
class Widget:
def __init_subclass__(cls):
name = cls.__name__
if not name[0].isupper() or not name.startswith("_"):
raise BadWidgetName(
f"Widget class {name!r} must start with an upper case letter or underscore '_'."
)
class A(Widget): # Ok
pass
class _b(Widget): # Ok
pass
class c(Widget): # raises BadWidgetName exception.
pass
+35 chapters. +400 pages. Hundreds of examples. Over 30,000 readers!
My book βPydon'tsβ teaches you how to write elegant, expressive, and Pythonic code, to help you become a better developer. >>> Download it here ππ.