2013-04-18 92 views
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调用基__init__第一,它调用runme(),这反过来将调用evaluate。由于孩子过度乘坐evaluate,执行的evaluate孩子的定义,但作为self.ad1还没有尚未被实例化,这将引发AttributeError

我可以从myBase删除self.runme(),问题很可能会消失,但我可以进一步sublcass childAchildAA

class childAA(childA): 
    def __init__(self,neg,op,value,ad1): 
     super(childAA,self).__init__(neg,op,value,ad1) 
     self.runme() 

而且问题都可以重新显现。因为可以形成既childAchildAA的对象,我不能从childA的__init__删除runme()(和需要处理)

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

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

一个更简单的方法是在孩子的__init__结束调用super(),但这并不出现是正确的

另一种方式是 - 告诉基类推迟调用邵仁枚的()到孩子班。这可能吗?在我的基地说,我做

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) 

这段代码可以放在被调用第一runme()

def preprocess(self): 
    self.internal_value = value 
    #Rest of the stuff 
+1

请看http://rhettinger.wordpress.com/2011/05/26/super-considered-super/;我认为如果'__init__'委托完成类的初始化,最后调用'super()'并不合逻辑。 – thkang 2013-04-18 07:02:35

+0

你为什么认为“那不合适”?这正是您在这种情况下所需要的,这是最简单的解决方案。我没有看到任何理由使用非常复杂的代码,只是因为有人告诉你_easy_解决方案看起来不正确。 – 2013-04-18 07:37:34

+0

@ running.t是的你是对的。其实我原来的解决方案并没有设想从子项中移除'runme()'调用。编辑了我的问题,包括我现在正在做的事情,因为两个人发布了相同的答案,然后将其删除 – RedBaron 2013-04-18 08:34:32

回答

0

如果儿童__init__需要部分初始化的对象进行了preprocess()或其他一些功能,在结束通话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]