2016-08-28 26 views
0

這裏BC都從A派生,但具有不同的__init__()參數。我的問題是如何在這裏編寫正確/優雅的代碼來初始化self.a,self.b,self.c1,self.c2,如下例所示: 也許還有一個問題是 - 在__init()__函數中做這個變量設置是否是一種很好的編碼習慣,或者稍後使用更簡單的__init__()函數以及爲每個類別做set()函數更好,這看起來不像做它那麼簡單在__init()__與父類的python多繼承有不同的__init __()

class A(object): 
    __init__(self,a): 
     self.a=a 
class B(A): 
    __init__(self,a,b): 
     super(B,self).__init__(a) 
     self.b=b 
class C(A): 
    __init__(self,a,c1,c2): 
     super(C,self).__init__(a) 
     self.c1=c1 
     self.c2=c2 

class D(B,C) 
    __init__(self,a,b,c1,c2,d): 
     #how to write the correct/elegant code here to initialize self.a,self.b,self.c1,self.c2? 
     #can I use super(D,self) something? 
     self.d=d 
     self.dd=self.a+self.b+2*self.c1+5*self.c2+3*self.d 

d=D(1,2,3,4,5) 
+0

謝謝你的評論@Karin,但這裏的問題是不同的,更開放。 –

回答

1

Python中的多重繼承需要所有的類協同工作。在這種情況下,您可以通過讓每個類中的__init__方法接受任意**kwargs使它們合作,並在它們調用super().__init__時將其傳遞。

對於示例類層次結構,你可以做這樣的事情:

class A(object): 
    __init__(self,a): # Don't accept **kwargs here! Any extra arguments are an error! 
     self.a=a 

class B(A): 
    __init__(self, b, **kwargs): # only name the arg we care about (the rest go in **kwargs) 
     super(B, self).__init__(**kwargs) # pass on the other keyword args 
     self.b=b 

class C(A): 
    __init__(self, c1, c2, **kwargs): 
     super(C,self).__init__(**kwargs) 
     self.c1=c1 
     self.c2=c2 

class D(B,C) 
    __init__(self, d, **kwargs): 
     super(D,self).__init__(**kwargs) 
     self.d=d 
     self.dd=self.a+self.b+2*self.c1+5*self.c2+3*self.d 

請注意,如果你想D直接(而不是使用self.a等)使用的參數值,你可以採取兩種他們作爲命名的參數,仍然把它們在super()呼叫:如果某些父類的不保存的參數(在他們origi

class D(B,C) 
    __init__(self,a, b, c1, c2, d, **kwargs): # **kwargs in case there's further inheritance 
     super(D,self).__init__(a=a, b=b, c1=c1, c2=c2, **kwargs) 
     self.d = d 
     self.dd = a + b + 2 * c1 + 5 * c2 + 3 * d # no `self` needed in this expression! 

接受和傳遞一些參數表是重要的最終形式)作爲屬性,但是你需要這些值。您也可以使用此類型的代碼傳遞某些參數的修改值(例如,使用super(D, self).__init__(a=a, b=b, c1=2*c1, c2=5*c2, **kwargs))。

這種具有不同參數的協作多重繼承幾乎不可能使用位置參數進行工作。不過,使用關鍵字參數時,名稱和值在調用中的順序無關緊要,因此可以輕鬆傳遞命名參數和**kwargs,而不會造成任何中斷。使用*args也不行(儘管Python 3的最新版本更加靈活,您可以通過*args調用函數,例如允許在一次調用中允許多個解壓縮:f(*foo, bar, *baz))。

如果你使用Python 3(我假設沒有,因爲你明確地傳遞參數給super),你可以使參數的協作功能「關鍵字只」,這將避免用戶得到非常混淆並試圖用位置參數來調用你的方法。只需在其他命名參數之前將參數列表中的*放入其中即可:def __init__(self, *, c1, c2, **kwargs):

+0

謝謝@Blckknght,這是非常好的解釋! –