想不出一个更好的问题标题。随意编辑。我有一个基类,它由许多类继承(反过来可能有更多的子类)。对于每个类,我有一系列操作需要执行后初始化。序列封装在函数runme()
中,该函数执行一系列对象方法调用
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
子类必须接受与base(以及任何其他属性)相同的属性。所有这些都将覆盖三个函数 - 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
我看到它的方式会产生问题 - childA
首先调用基础__init__
,调用runme()
,然后调用evaluate
。evaluate
由于孩子超越了evaluate
,孩子对self.ad1
的定义已经执行,但由于AttributeError
尚未尚未实例化,因此会引发self.runme()
}
我可以从myBase中移除childA
,问题可能会消失,但我可以进一步将childAA
转入class childAA(childA):
def __init__(self,neg,op,value,ad1):
super(childAA,self).__init__(neg,op,value,ad1)
self.runme()
runme()
问题可以再次出现。我无法从childA的__init__
中移除childA
,因为childAA
和runme()
的对象都可以形成(并且需要处理)
目前,作为一种变通方法,我不会在__init__
中调用obja=childA(foo,bar,baz,ad1)
obja.runme()
,而是在初始化后从调用程序中调用它。
super()
更简单的替代方法是在孩子的__init__
结束时拨打def __init__(self,neg,op,value):
self.neg = neg
self.op = op
self.value = value
#Process
if some_condition which checks if this is being called by a derived class:
self.runme()
,但
另一种方法是 - 告诉基类将runme()的调用推迟到子类。这可能吗?在myBase中说,我做
runme()
如果这些是解决它的最佳方法?或者,这是一个常见问题,还有其他建议的解决方案?
修改
发布(并删除)了两个答案,同意最好的方法是将super()
调用留在基类中,然后在结束时调用__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)
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)
如果您需要依赖于现有值的值,
preprocess()
此代码可以放在runme()
或def preprocess(self):
self.internal_value = value
#Rest of the stuff
{{1}}
答案 0 :(得分:0)
如果孩子的__init__
需要部分初始化的对象继续进行,那么最后调用super()
将无法正常工作。如果是这种情况,您可以在runme
中致电__new__
表单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
您可以按照初始化过程的要求在各种__init__
函数内部对代码进行排序,并且在runme
完成后始终会调用正确的__init__
函数:
>>> 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]