繁体   English   中英

部分初始化基类

[英]Partially initializing base class

想不到一个更好的问题标题。 随时编辑。 我有一个由许多类继承的基类(而基类又可能有更多的子类)。 对于每个类,我都有执行初始化后所需的一系列操作。 序列封装在函数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() ,问题可能会消失,但是我可以进一步将childA childAAchildAA

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

问题会再次出现。 我无法从childA的__init__删除runme() ,因为childAchildAA对象都可以形成(并且需要处理)

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

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

一个更简单的替代方法是调用super()在孩子的结束__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()调用留在基类中,然后在孩子的__init__ 末尾调用super()

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

如果孩子的__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__函数中订购代码,并且在__init__完成后,始终会调用正确的runme函数:

>>> 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]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM