[英]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
子類必須接受與基相同的屬性(以及任何其他屬性)。 它們都將超越三個功能- preprocess
, evaluate
和postprocess
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
childAA
為childAA
class childAA(childA):
def __init__(self,neg,op,value,ad1):
super(childAA,self).__init__(neg,op,value,ad1)
self.runme()
問題會再次出現。 我無法從childA的__init__
刪除runme()
,因為childA
和childAA
對象都可以形成(並且需要處理)
當前,作為一種解決方法,我不在__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.