在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()