簡體   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