python - Partially initializing base class -
couldn't think of better question title. feel free edit. have base class inherited many classes (which in turn may have more sub-classes). each class, have sequence of operations need perform post-initialization. sequence encapsulated in function runme()
performs series of object method calls
class mybase(object): def __init__(self,neg,op,value): self.neg = neg self.op = op self.value = value #process self.runme() def runme(self): self.preprocess() self.evaluate() self.postprocess() def preprocess(self): pass def evaluate(self): pass def postprocess(self): pass
the sub-classes have accept same attributes base (and additional attributes). of them over-ride 3 functions - preprocess
, evaluate
, postprocess
class childa(mybase): def __init__(self,neg,op,value,ad1): super(childa,self).__init__(neg,op,value) self.ad1 = ad1 #must call runme() here again?? runme() def evaluate(): #something using self.ad1 blah = self.ad1+self.value
the way see it, creates problem - childa
calls base __init__
first, calls runme()
, in turn call evaluate
. since child over-rides evaluate
, child's definition of evaluate
executed, self.ad1
has not yet been instantiated, throws attributeerror
i can remove self.runme()
mybase , problem gone, can further sublcass childa
childaa
class childaa(childa): def __init__(self,neg,op,value,ad1): super(childaa,self).__init__(neg,op,value,ad1) self.runme()
and problem can manifest on again. can't remove runme()
childa's __init__
because objects of both childa
, childaa
can formed (and need processing)
currently, workaround, not call runme()
in __init__
, instead call calling program after initialization.
obja=childa(foo,bar,baz,ad1) obja.runme()
a simpler alternative call super()
@ end of child's __init__
, not appear right
another way - tell base class defer calling of runme() child class. possible? in mybase, do
def __init__(self,neg,op,value): self.neg = neg self.op = op self.value = value #process if some_condition checks if being called derived class: self.runme()
which if these best way solve it? alternatively, common problem , other suggested solutions?
edit
two answers posted (and deleted) concurred best way seems to leave runme()
call in base-class , call super()
@ end of child's __init__
class mybase(object): def __init__(self,neg,op,value): self.neg = neg self.op = op self.value = value #process self.runme() class childa(mybase): def __init__(self,neg,op,value,ad1): self.ad1 = ad1 super(childa,self).__init__(neg,op,value)
in case need values depend on existing values,
class childa(mybase): def __init__(self,neg,op,value,ad1): self.ad1 = ad1 self.internal_value = self.value #not yet initialized!! super(childa,self).__init__(neg,op,value)
this code can put in preprocess()
or other function gets called first in runme()
def preprocess(self): self.internal_value = value #rest of stuff
if children's __init__
require partially initialized objects proceed, calling super()
@ end not work indeed. if that's case, call runme
form __new__
in mybase
:
class mybase(object): def __new__(cls, *args, **kwargs): obj = super(mybase, cls).__new__(cls) obj.__init__(*args, **kwargs) obj.runme() def __init__(self, a): print 'mybase init' self.list = ['mybase', a] def runme(self): print 'mybase:', self.list class childa(mybase): def __init__(self, a, b): print 'childa init' super(childa, self).__init__(a) self.list.extend(['childa', b]) def runme(self): print 'childa:', self.list class childaa(childa): def __init__(self, a, b, c): print 'childaa init' super(childaa, self).__init__(a, b) self.list.extend(['childaa', c]) def runme(self): print 'childaa:', self.list
you can order code inside various __init__
functions required initialisation process, , proper runme
function called after __init__
completes:
>>> childa(1, 2) childa init mybase init childa: ['mybase', 1, 'childa', 2] >>> childaa(1, 2, 3) childaa init childa init mybase init childaa: ['mybase', 1, 'childa', 2, 'childaa', 3]
Comments
Post a Comment