Python __init_subclass__ Method
Last modified April 8, 2025
This comprehensive guide explores Python's __init_subclass__
method,
a hook for customizing subclass creation. We'll cover basic usage, class
registration, plugin systems, validation, and practical examples.
Basic Definitions
The __init_subclass__
method is called when a class is subclassed.
It provides a way to customize subclass creation without using metaclasses.
Key characteristics: it's a class method (but doesn't need decorator), receives the subclass as argument, and runs during class definition. Introduced in Python 3.6 as a simpler alternative to metaclasses for many use cases.
Basic __init_subclass__ Implementation
Here's the simplest implementation showing how __init_subclass__
works. It demonstrates the basic structure and when it gets called.
class Base: def __init_subclass__(cls, **kwargs): print(f"Subclass {cls.__name__} created") super().__init_subclass__(**kwargs) class Child(Base): pass # Output: "Subclass Child created"
This example shows the basic pattern. When Child inherits from Base,
__init_subclass__
is automatically called with the Child class.
The **kwargs
captures any additional keyword arguments passed in
the class definition. Always call super() to support cooperative inheritance.
Class Registration Pattern
__init_subclass__
is commonly used to implement class registration,
where subclasses are automatically tracked by a parent class.
class PluginRegistry: plugins = [] def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) PluginRegistry.plugins.append(cls) class PluginA(PluginRegistry): pass class PluginB(PluginRegistry): pass print(PluginRegistry.plugins) # [<class '__main__.PluginA'>, <class '__main__.PluginB'>]
This implementation automatically collects all plugin classes that inherit from PluginRegistry. The registry can then be used to instantiate or inspect plugins.
This pattern is useful for plugin systems where you want to discover all available implementations without explicitly registering them.
Adding Class Attributes
__init_subclass__
can modify subclasses by adding or modifying
class attributes during creation.
class Document: def __init_subclass__(cls, doc_type=None, **kwargs): super().__init_subclass__(**kwargs) if doc_type is not None: cls.doc_type = doc_type class PDF(Document, doc_type="application/pdf"): pass class Word(Document, doc_type="application/msword"): pass print(PDF.doc_type) # "application/pdf" print(Word.doc_type) # "application/msword"
This example shows how to add type information to document classes. The
doc_type
parameter is passed during class definition.
The method checks for the parameter and adds it as a class attribute if present. This pattern is useful for declarative class definitions.
Subclass Validation
__init_subclass__
can validate subclass definitions, ensuring they
meet certain requirements.
class Shape: def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) if not hasattr(cls, 'area'): raise TypeError(f"Subclass {cls.__name__} must implement 'area' method") class Circle(Shape): def area(self): return 3.14 * self.radius ** 2 # class Square(Shape): # Would raise TypeError # pass
This implementation ensures all Shape subclasses implement an area
method. The check happens during class creation, failing fast if requirements
aren't met.
This is more maintainable than checking at runtime and provides clearer error messages during development.
Plugin System with Configuration
A more advanced plugin system can use __init_subclass__
to handle
plugin configuration and registration.
class PluginSystem: _plugins = {} def __init_subclass__(cls, name=None, **kwargs): super().__init_subclass__(**kwargs) if name is None: name = cls.__name__.lower() if name in PluginSystem._plugins: raise ValueError(f"Plugin {name} already exists") PluginSystem._plugins[name] = cls @classmethod def get_plugin(cls, name): return cls._plugins.get(name) class DatabasePlugin(PluginSystem, name="db"): pass class CachePlugin(PluginSystem, name="cache"): pass print(PluginSystem.get_plugin("db")) # <class '__main__.DatabasePlugin'>
This implementation adds named registration and duplicate prevention. Plugins must provide unique names, which are used to retrieve them later.
The system demonstrates how __init_subclass__
can manage more
complex registration scenarios while keeping the class definitions clean.
Best Practices
- Always call super(): Ensures cooperative multiple inheritance
- Document expected kwargs: Clearly document parameters subclasses should pass
- Keep it simple: Avoid complex logic that might make debugging hard
- Prefer over metaclasses: Use instead of metaclasses when possible
- Validate early: Do validation during subclass creation
Source References
Author
List all Python tutorials.