1

想不出更好的问题标题。随意编辑。我有一个基类,它被许多类继承(而这些类又可能有更多的子类)。对于每个类,我都有一系列需要执行初始化后的操作。该序列被封装在一个函数中,该函数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

子类必须接受与基类相同的属性(以及任何附加属性)。它们都将覆盖三个函数-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调用 base __init__,然后调用runme(),然后调用evaluate. 由于 child over-rides evaluate,child 的定义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__因为两者的对象都可以形成(并且需要处理childAchildAA

目前,作为一种解决方法,我不调用runme()__init__而是在初始化后从调用程序中调用它。

obja=childA(foo,bar,baz,ad1)
obja.runme()

super()一个更简单的替代方法是在 child's 的末尾调用,但这似乎__init__不正确

另一种方法是 - 告诉基类将 runme() 的调用推迟到子类。这可能吗?在 myBase 中说,我愿意

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()在基类中留下电话,然后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
4

1 回答 1

0

如果孩子们__init__需要部分初始化的对象才能继续,super()那么最后的调用确实不起作用。如果是这种情况,您可以调用runmeform __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

__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]
于 2013-04-18T07:30:45.847 回答