How to perform common post-initialization tasks in inherited classes?
Solution 1
Version 1 - delegate everything.
class Subclass1(BaseClass):
def __init__(self):
super( Subclass1, self ).__init__()
self.specific()
super( Subclass1, self ).finalizeInitialization()
Version 2 - delegate just one step
class BaseClass:
def __init__(self):
print 'base __init__'
self.common1()
self.specific()
self.finalizeInitialization()
def common1(self):
print 'common 1'
def finalizeInitialization(self):
print 'finalizeInitialization [common2]'
def specific( self ):
# two choices:
# if this is "abstract": raise an exception
# if this is "concrete": pass
Solution 2
Template Method Design Pattern to the rescue:
class BaseClass:
def __init__(self, specifics=None):
print 'base __init__'
self.common1()
if specifics is not None:
specifics()
self.finalizeInitialization()
def common1(self):
print 'common 1'
def finalizeInitialization(self):
print 'finalizeInitialization [common2]'
class Subclass1(BaseClass):
def __init__(self):
BaseClass.__init__(self, self.specific)
def specific(self):
print 'specific'
Solution 3
You can use metaclasses (and updated to Python3 code):
class PostInitCaller(type):
def __call__(cls, *args, **kwargs):
obj = type.__call__(cls, *args, **kwargs)
obj.__post__init__()
return obj
class BaseClass(metaclass=PostInitCaller):
def __init__(self):
print('base __init__')
self.common1()
def common1(self):
print('common 1')
def finalizeInitialization(self):
print('finalizeInitialization [common2]')
def __post__init__(self): # this is called at the end of __init__
self.finalizeInitialization()
class Subclass1(BaseClass):
def __init__(self):
super().__init__()
self.specific()
def specific(self):
print('specific')
s = Subclass1()
Solution 4
Similar to S. Lott's approach, except there's no way (short of overriding __init__
) for the derived classes to override (or even call) the common methods:
class BaseClass:
def __init__(self):
def common():
print "common initialization..."
def final():
print "common finalization..."
common()
self.specific()
final()
def final_init(self):
print "BaseClass.final_init"
class Subclass1(BaseClass):
def specific(self):
print "Subclass1.specific"
You might want to provide a default implementation of specific
in BaseClass
if it's not okay to raise an AttributeError
when you create an instance of any subclass that doesn't provide its own implementation.
Boris Gorelik
Updated on July 01, 2022Comments
-
Boris Gorelik about 2 years
The initialization process of a group of classes that share a common parent can be divided into three parts:
- Common initialization
- Subclass-specific initialization
- Common post-initialization
Currently the first two parts are called from the
__init__
method of each child class, but the final post-initialization part has to be called separately, for exampleclass BaseClass: def __init__(self): print 'base __init__' self.common1() def common1(self): print 'common 1' def finalizeInitialization(self): print 'finalizeInitialization [common2]' class Subclass1(BaseClass): def __init__(self): BaseClass.__init__(self) self.specific() def specific(self): print 'specific' if __name__ == '__main__': s = Subclass1() # Don't forget to finalize the initialization s.finalizeInitialization() # now the object is fully initialized
Is there a way to not to have to call
finalizeInitialization()
? Or one can transfer the call tofinalizeInitialization()
intoSubclass1
's__init__
(as in S.Lott's answer). This makes the life easier, but still one has to remember to complete the initialization, this time inside the "constructor". Either way there is no way to enforce full initialization, which is what I'm looking for. -
Dan Niero over 2 yearsThe most elegant solution