当前位置: 首页 > 后端技术 > Python

类继承中的super()

时间:2023-03-26 13:05:29 Python

在python中,有很多关于类继承的场景和知识点。今天重点关注一个场景:有一个父类A,定义了某个问题中的通用属性和方法(也就是后面需要用到所有的子类),这些属性和方法需要在子类B中继承,并且同时如何添加自己独特的属性和方法?在子类中,继承和初始化父类的属性有两种方式:显式调用父类的初始化函数,对属性进行初始化;通过super()初始化父类的属性;对于方法1,代码:classA:def__init__(self,a,b):self.a=aself.b=bdeffunc(self):returnself.a+self.bclassB(A):def__init__(self,x1,x2,x3,x4):A.__init__(self,a=x1,b=x2)#注意必须传入self,相当于传入B的实例self.c=x3self.d=x4self.m=A.func(self)#也必须传入selfself.n=self.func()>>>ins=B(1,2,10,20)>>>print(ins.a,ins.b,ins.c,ins.d)121020>>>print(ins.m,ins.n)33>>>print(ins.func())3对于方法二,代码:classA:def__init__(self,a,b):self.a=aself.b=bdeffunc(self):returnself.a+self.bclassB(A):def__init__(自我,x1,x2,x3,x4):超级()。__init__(a=x1,b=x2)#初始化父类参数,注意不需要selfself.c=x3self.d=x4self.m=super().func()#super()也可以调用父类方法self.n=self.func()#也可以直接调用使用父类方法>>>ins=B(1,2,10,20)>>>print(ins.a,ins.b,ins.c,ins.d)121020>>>print(ins.m,ins.n)33>>>print(ins.func())3对于方法1,初始化显示调用,多重继承时可能会出现重复调用,如:classA:def__init__(self,a,b):self.a=aself.b=bprint('AAAAA')deffunc(self):returnself.a+self.bclassB(A):def__init__(self,x1,x2,x3,x4):A.__init__(self,a=x1,b=x2)self.c=x3self.d=x4print('BBBBB')classC(A):def__init__(self,m,n,q):A.__init__(self,m,n)self.q=qprint('CCCCC')类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=fprint('DDDDDD')>>>ins=D(1,2,3),4,5,6)AAAAAABBBBBAAAAACCCCCDDDDDD可以看到A被调用了两次,因为D继承了B和C,初始化B的时候会先初始化A,再初始化B;初始化C时,也会先初始化A,再初始化C;因此A被初始化了两次。还有一个问题就是,虽然使用super()可以避免重复调用的问题,但是当父类有参数需要初始化的时候就很麻烦了:classA:def__init__(self):print('AAAAA')deffunc(self):返回self.a+self.bclassB(A):def__init__(self):super().__init__()print('BBBBB')classC(A):def__init__(self):super().__init__()print('CCCCC')classD(B,C):def__init__(self):super().__init__()print('DDDDDD')>>>ins=D()AAAAACCCCCBBBBBDDDDDD#可见,确实可以避免重复调用的问题。但是,如果父类有参数,那么这时候问题就很大了,比如:classA:def__init__(self,a,b):self.a=aself.b=bprint('AAAAA')deffunc(self):返回self.a+self.b类B(A):def__init__(self,x1,x2,x3,x4):super().__init__(x1,x2)self.c=x3self.d=x4print('BBBBB')C类(A):def__init__(self,m,n,q):super().__init__(m,n)self.q=qprint('CCCCC')classD(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=fprint('DDDDDD')>>>ins=D(1,2,3,4,5,6)TypeError:__init__()missing1requiredpositionalargument:'q'>>>print(D.__mro__)#查看D的父类调用MRO的顺序(,,,,)#因此。可以看到第一次调用的是B,初始化成功;而初始化C时报错,C中的m和n都在初始化A,而A在上一步已经初始化过了。但是因为所有的参数都输入了B,初始化C的时候少了一个参数q,所以报错。对于带参数的多重继承问题,另一个类似的例子可以参考:https://www.pythonf.cn/read/1...所以,对于带参数的多重继承问题,使用super()会非常困难要用的话,不如用displaycalls,小问题就是有些类会被反复初始化。再者,在python中尽量不要使用多重继承,这样会使结构非常复杂,代码也很脆弱。在单继承场景中,可以使用显式调用或super()。请注意,要么显式调用所有类,要么所有类都使用super()