在python中,關於類的繼承有不少場景和知識點。今天聚焦在一個場景:有一個父類A,類中定義了某個問題中的通用屬性和方法(即後面的子類都須要用到),在子類B中須要繼承這些屬性和方法,同時添加本身特有的屬性和方法,應該如何實現?python
在子類中,繼承並初始化父類屬性的方式有兩種:函數
對於方式1,代碼:ui
class A: def __init__(self,a,b): self.a=a self.b=b def func(self): return self.a+self.b class B(A): def __init__(self,x1,x2,x3,x4): A.__init__(self,a=x1,b=x2)#注意必需要傳入self,至關於把B的實例傳進去 self.c=x3 self.d=x4 self.m=A.func(self)#一樣必須傳入self self.n=self.func() >>>ins=B(1,2,10,20) >>>print(ins.a,ins.b,ins.c,ins.d) 1 2 10 20 >>>print(ins.m,ins.n) 3 3 >>>print(ins.func()) 3
對於方式2,代碼:code
class A: def __init__(self,a,b): self.a=a self.b=b def func(self): return self.a+self.b class B(A): def __init__(self,x1,x2,x3,x4): super().__init__(a=x1,b=x2)#初始化父類參數,注意不須要self了 self.c=x3 self.d=x4 self.m=super().func()#super()一樣能調用父類的方法 self.n=self.func()#也能夠直接調用父類方法 >>>ins=B(1,2,10,20) >>>print(ins.a,ins.b,ins.c,ins.d) 1 2 10 20 >>>print(ins.m,ins.n) 3 3 >>>print(ins.func()) 3
對於方式1,顯示調用進行初始化,在多重繼承的時候可能會出現重複調用的問題,如:繼承
class A: def __init__(self,a,b): self.a=a self.b=b print('AAAAA') def func(self): return self.a+self.b class B(A): def __init__(self,x1,x2,x3,x4): A.__init__(self,a=x1,b=x2) self.c=x3 self.d=x4 print('BBBBB') class C(A): def __init__(self,m,n,q): A.__init__(self,m,n) self.q=q print('CCCCC') class D(B,C): def __init__(self,a,b,c,d,e,f): B.__init__(self,a,b,c,d) C.__init__(self,a,b,e) self.f=f print('DDDDDD') >>>ins=D(1,2,3,4,5,6) AAAAA BBBBB AAAAA CCCCC DDDDDD
能夠看到,A被調用了兩次。由於D繼承了B和C,在初始化B的時候,首先會初始化A,而後初始化B;在初始化C的時候,也會先初始化A,再初始化C;所以A就被初始化了兩次。get
另外一個問題是,it
而用super()雖然能夠避免重複調用這個問題,可是在父類均有參數須要初始化時就很麻煩:io
class A: def __init__(self): print('AAAAA') def func(self): return self.a+self.b class B(A): def __init__(self): super().__init__() print('BBBBB') class C(A): def __init__(self): super().__init__() print('CCCCC') class D(B,C): def __init__(self): super().__init__() print('DDDDDD') >>>ins=D() AAAAA CCCCC BBBBB DDDDDD #可見,確實能夠避免重複調用的問題。
可是,若是父類均有參數,那麼這個時候問題就很大了,如:class
class A: def __init__(self,a,b): self.a=a self.b=b print('AAAAA') def func(self): return self.a+self.b class B(A): def __init__(self,x1,x2,x3,x4): super().__init__(x1,x2) self.c=x3 self.d=x4 print('BBBBB') class C(A): def __init__(self,m,n,q): super().__init__(m,n) self.q=q print('CCCCC') class D(B,C): def __init__(self,a,b,c,d,e,f): super().__init__(a,b,c,d)##這種狀況下,由於是按照MRO法則來以此對全部父類進行初始化,所以這裏不管怎麼傳參數,都是有可能報錯的。由於不一樣父類的入參不一樣。根據後面查看的MRO順序,調用順序是D-B-C-A,所以這裏初始化的時候IDE會提示輸入4個參數,由於首先調用的是B,而B的初始化須要4個參數。 self.f=f print('DDDDDD') >>>ins=D(1,2,3,4,5,6) TypeError: __init__() missing 1 required positional argument: 'q' >>>print(D.__mro__)#查看D的父類調用MRO順序 (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) #所以。能夠看到,首先調用的是B,初始化成功;而在初始化C的時候報錯,C中的m,n都是初始化A,而A已經在前一步初始化過了。可是由於全部的參數都進了B,如今初始化C的時候缺一個參數q,所以報錯。
對於帶參數的多重繼承問題,另外一個一樣的例子能夠參考來理解:https://www.pythonf.cn/read/1...require
所以,對於帶參數的多重繼承問題,使用super()會很是難用,不如使用顯示調用,帶來的小問題是部分類會重複初始化。
更進一步,在python中儘可能不要使用多重繼承,會讓結構顯得很是複雜,代碼也變得脆弱。在單繼承場景中,則顯示調用或者super()均可以使用,注意,要麼所有類都顯示調用,要麼所有都用super()