部分初始化基类

时间:2013-04-18 06:40:36

标签: python inheritance python-2.6

想不出一个更好的问题标题。随意编辑。我有一个基类,它由许多类继承(反过来可能有更多的子类)。对于每个类,我有一系列操作需要执行后初始化。序列封装在函数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(以及任何其他属性)相同的属性。所有这些都将覆盖三个函数 - preprocessevaluatepostprocess

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(),然后调用evaluateevaluate由于孩子超越了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,因为childAArunme()的对象都可以形成(并且需要处理)

目前,作为一种变通方法,我不会在__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}}

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]