I have a class hierarchy where
class Base performs some pre-initialization and then calls method
calculate method is defined in
class Base, but it's expected to be redefined in derived classes. The redefined
calculate will use some of the attributes that are only available in
class Base: def __init__(self, args): # perform some pre-initialization ... # now call method "calculate" self.calculate() class Derived(Base): def __init__(self, args, additional_attr): super().__init__(args) # do some work and create new instance attributes ... self.additional_attr = additional_attr
This is not going to work because
calculate method in
class Derived will be invoked before self.additional_attr is assigned.
I can't move
super().__init__(args) call to the end of the
__init__ method because some of the work it does has to happen before processing
What to do?
Perhaps you shouldn't have the
calculate() call in your constructor then. If you can't construct a derived object by allowing the base constructor to complete first, then you must be doing something wrong IMHO. A sensible approach would be to move that call out of the constructor and perhaps create a factory method to make that call automatically. Then use that method if you need precalculated instances.
class Base(object): def __init__(self, args): # perform some initialization pass def calculate(self): # do stuff pass @classmethod def precalculated(cls, args): # construct first newBase = cls(args) # now call method "calculate" newBase.calculate() return newBase class Derived(Base): def __init__(self, args, additional_attr): super(Derived, self).__init__(args) # do some work and create new instance attributes self.additional_attr = additional_attr @classmethod def precalculated(cls, args, additional_attr): # also if you want newDerived = cls(args, additional_attr) newDerived.calculate() return newDerived newBase = Base('foo') precalculatedBase = Base.precalculated('foo') newDerived = Derived('foo', 'bar') precalculatedDerived = Derived.precalculated('foo', 'bar')
This is bad design, IMHO, and you're obusing the object system of Python. Consider that in other OO languages like C++, you don't even have control over the creation of base classes. The derived class's constructor calls the base constructor before your code runs. Such behavior is almost always expected of well-behaved class hierarchies, and changing it can only lead to problems.
Sure, you can do some patching (such as assigning
self.additional_attr before the call to
super's constructor, or other tricks), but the better way would be to change your design so that it won't require such hacks. Since you've presented an abstract example here, it's hard to give more comprehensive design advice.