Metaprogramming β __dunder__, slots & meta
Go deep into Python's object model β metaclasses, __init_subclass__, __class_getitem__, descriptors, and runtime class manipulation.
Part 1: What You Will Learn
- Use common dunder methods to customise object behaviour.
- Understand how
__slots__restricts instance attributes. - Register subclasses automatically with
__init_subclass__. - See how metaprogramming can build plugin systems without manually maintaining a registry.
Part 2: Key Concepts
Metaprogramming is code that changes, creates, or configures program structures. Python exposes many hooks through special methods. These techniques are powerful, so they should be used when they simplify a framework or reusable componentβnot merely to make ordinary code more clever.
Part 3: Topic-Specific Code Example
class ReportPlugin:
registry: dict[str, type["ReportPlugin"]] = {}
def __init_subclass__(cls, *, name: str, **kwargs) -> None:
super().__init_subclass__(**kwargs)
ReportPlugin.registry[name] = cls
cls.plugin_name = name
def generate(self, data: list[int]) -> str:
raise NotImplementedError
class SummaryReport(ReportPlugin, name="summary"):
__slots__ = ()
def generate(self, data: list[int]) -> str:
return f"Count={len(data)}, Total={sum(data)}"
class AverageReport(ReportPlugin, name="average"):
__slots__ = ()
def generate(self, data: list[int]) -> str:
return f"Average={sum(data) / len(data):.2f}"
def create_report(name: str) -> ReportPlugin:
plugin_class = ReportPlugin.registry[name]
return plugin_class()
numbers = [12, 18, 25, 30]
for name in ReportPlugin.registry:
report = create_report(name)
print(name, "->", report.generate(numbers))
print("Registered:", ReportPlugin.registry)Part 4: How the Example Works
Whenever a subclass of ReportPlugin is created, __init_subclass__() automatically stores it in the registry. This is a simple form of metaprogramming because class creation itself triggers configuration. The concrete plugins use __slots__ = () because they do not need per-instance attributes.
Part 5: Hands-On Practice
Mini project β Command Plugin System. Create a base Command class that automatically registers subclasses such as HelloCommand, DateCommand, and HelpCommand. Let the user type a command name and instantiate the matching class from the registry.
Part 6: Next Steps
Experiment with __repr__, __len__, and class registration, then continue to Lesson 35 for profiling and performance optimisation.