Posts for: #Metaprogramming
Patterns for Customizing Class Creation
__init_subclass__ was introduced in PEP 487 and according to James Powell covers every use that was previously done in metaclasses (with the one exception being implementation of protocols on types). It’s main purpose was to customize subclass creation
Just to get it out of the way, let’s see the order in which these functions are called (the other functions being __new__ and __init__)
class Parent:
def __init__(self, *args, **kwargs) -> None:
print('Parent __init__')
def __new__(cls, *args, **kwargs):
print('Parent __new__')
return super().__new__(cls, *args, **kwargs)
def __init_subclass__(cls):
print('__init_subclass__')
class Child(Parent):
def __init__(self, *args, **kwargs):
print('Child __init__')
super().__init__(*args, **kwargs)
__init_subclass__
We see that __init_subclass__ is run at time of child class creation, NOT instance creation
Metaclass for Auto Initialization
Experiments customizing __new__ in Python
object.__new__(cls[, ...])
__new__ is called to create a new instance of class cls. It is a static method, which takes the class of which an instances was requested as its first argument. Remaining are arguments passed into the constructor. The return value should be a new object instance (if this is not returned, the instance is not created)
Typically call super().__new(cls[, ...]).
__init__ vs __new__
According to the python docs, __new__ was for customizing instance creation when subclassing built-int types. Since it’s invoked before __init__, it is called with the CLASS as it’s first argument (whereas __init__ is called with an instance as its first and doesn’t return anything)
Enforcing Function Implementation in Subclasses
This is going to get very weird, very quickly. When you create a class in Python, it looks about like the following:
class MyClass:
pass
Now, let’s say I create some really cool class, with a set of cool functions, but I expect my users to implement some of the functions:
from abc import abstractmethod
class BaseClass:
@abstractmethod
def foo(self,):
raise NotImplementedError
So the intention is, when my user inherits the above class, they do the following: