Python: patching a class from a parent's __init__
In python some classes expect to have a property defined in a
subclass, like django migrations require the member
operations.
In some cases it is necessary to make this property dynamic for all the subclasses at the same time.
In that case overwriting the property with a property method is one way forward 1️⃣:
from functools import partial
class Test:
def __init__(self):
self.__class__.operations = property(partial(self.__class__.ass_name,
original_operations=self.__class__.operations))
def ass_name(self, original_operations):
return original_operations + 1
class SubTest(Test):
operations = 5
print(SubTest.operations) # it prints 5
print(SubTest().operations) # it prints 6
print(SubTest.operations) # it prints dynamic property
One way to think about this is that the parent __init__ method
is acting as a metaclass by patching the class definition.
So an easy alternative is to use a metaclass 2️⃣, but it might interfere with other metaclasses and it is also a bit harder to reason about.
It is also possible to patch the class variable with an instance variable 3️⃣
class Test:
def __init__(self):
self.operations += 1
but that has the tradeoff of requiring instantiation, which might not be possible to control for some classes like django’s migrations. It is also not fully dynamic
Lastly, __init_subclass__
pep 4874️⃣ also serves the same
purpose of patching the subclass from a single point.
from functools import partial
class Test:
def __init_subclass__(cls, increment):
cls.operations += increment
class SubTest(Test, increment=1):
operations = 5
print(SubTest.operations) # prints 6
print(SubTest().operations) # prints 6
print(SubTest.operations) # prints 6
This method also affects the property forever like 1️⃣ and can be combined with a dynamic property.
In general these tradeoffs are a byproduct of inheritance of classes that are beyond the scope of the current code and opinionated in some way.
- [[]]