1.super基本用法
在pyhont类的继承中,我们经常重写方法来覆盖父类的同名方法。但是如果我们想实现父类的方法,就需要用到super。
看一个例子:
class A:
def __init__(self):
print('A')
class B(A):
def __init__(self):
print('B')
#super(B,self).__init__() python2的用法
super().__init__() #python3的用法
在本例中,B继承A,在B的__init__方法中先打印出了自己的B,然后利用super调用了父类的__init__打印出了A(注:在python2和3中,调用super时有不同的形式)
2.具体应用场景
from threading import Thread
class MyThread(Thread):
def __init__(self,name,user):
self.user = user
super().__init__(name=name)#可将构造函数交给了父类,让父类实例化--重用代码
在threading源码中,实际上已经实现了__init__函数,该函数里面有很多参数,包括name,我们的MyThread子类去继承它后,使用super().init(name=name)来将构造函数交给了父类,让父类去进行实例化,实际上这体现了代码重用。
我们都会觉得,super就是用来调用父类方法的,但是真的是这样吗?当涉及到多重继承(菱形继承)时,super的调用顺序是什么?
3.super本质上和父类并无关联
#基类
class A:
def __init__(self):
print('A')
class B(A):
def __init__(self):
print('B')
super().__init__() #python3
class C(A):
def __init__(self):
print('C')
super().__init__() #python3
class D(B,C):
def __init__(self):
print('D')
super(D,self).__init__() #python2
if __name__ == '__main__':
d = D()
#print(D.__mro__)
体现了这样一种继承关系:
我们打印一下结果:
可以看到,如果你认为 super 代表去调用父类的方法,那么打印完B本应该去打印它的父类A,但是却去打印了C,原因是,super 和父类没有实质性的关联,现在让我们搞清 super 是按什么方式运行的。
4.mro 列表
mro:方法解析顺序(Method Resolution Order, MRO)列表,在继承中,它代表了类继承的顺序,是一种在多重继承中用于确定方法搜索顺序的算法,该顺序是根据C3线性化算法来定义的
我们可以使用print(D.__mro__)
来查看mro顺序:
mro遵循以下三个原则:
- 子类会先于父类被检查
- 多个父类会根据它们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类
我们看一下super函数的原型:
super(cls, inst):
mro = inst.__class__mro()
return mro(mro.index(cls) + 1)
cls 代表类,inst 代表实例
super做了两件事情:
- 获取mro列表
- 然后返回列表中的下一个类
当使用 super(cls, inst) 时,Python 会在 inst 的 MRO 列表上搜索 cls 的下一个类
在我们上面的例子中,super(D,self).__init__()
,D的下一个类是B,调到B的__init__先打印出B,再执行super().__init__()
,然后搜索mro中的下一个类,即C,打印出C并继续执行其__init__方法,而不是打印A!!!