【引用】https://www.cnblogs.com/chenhuabin/p/10058594.html
添加了个人的理解
1.MRO(Method Resolution Order):方法解析顺序
MRO其实就是以祖先类(包括父类)对于子类的重要性(优先级)来生成的一个序列。当类对象调用某个方法时,解释器会根据MRO列表去挨个找,直到找到一个同名的方法然后调用之。
目前Python3采用C3算法获得顺序。对于不同的类,它的mro不同。
C3算法:
1>将入度(指向该节点的箭头数量)为零的节点放入列表,左侧优先
2>将该节点及与该节点有关的箭头从上图树中删除
3>反复以上两个步骤,直到把所有节点都放入列表
以下图过一遍C3算法
F的mro顺序生成如下
步骤 | List |
---|---|
取F,删除F相关的箭头 | F |
取D(左侧优先),删除D相关的箭头 | F→D |
取A(A相对于E是左侧),删除A相关的箭头 | F→D→A |
取E,删除E相关的箭头 | F→D→A→E |
取B,删除B相关的箭头 | F→D→A→E→B |
取C,删除C相关的箭头 | F→D→A→E→B→C |
最后得到的顺序即:F->D->A->E->B->C->object.
同理可得:
E的mro顺序生成:E->B->C->object.
D的mro顺序生成:D->A->B->object.
A的mro顺序生成:A->object.
B的mro顺序生成:B->object.
C的mro顺序生成:C->object.
可用下面的代码运行观察:
class A(object):
def fun(self):
print('A.fun')
class B(object):
def fun(self):
print('B.fun')
class C(object):
def fun(self):
print('C.fun')
class D(A,B):
def fun(self):
print('D.fun')
class E(B, C):
def fun(self):
print('E.fun')
class F(D, E):
def fun(self):
print('F.fun')
print(F.__mro__)
print(E.__mro__)
print(D.__mro__)
print(A.__mro__)
2.super是用来引用父类的,可以完美的在多继承的情况下引用父类。
例1:
class A:
def fun(self):
print('A.fun')
class B(A):
def fun(self):
super(B , self).fun()
print('B.fun')
最常用的形式:super(类名,self).init()
例2:
class A(Parents):
def __init__(self):
super(A,self).__init__()
print '引用父类的初始化'
3.super的三种调用方法
super().方法
super(type , obj).方法
super(type_1 , type_2).方法
注意:super 的第一个参数尽量为当前的类。
①super(type , obj).方法
第二个参数是type参数类的实例化对象,也可以是该类的子类的实例化对象。obj用于确定搜索的MRO。即:用obj的MRO序列进行搜索
第一个参数type必须是一个类名。对于MRO的搜索会从 type 之后的类开始。
例:用上面介绍MRO的图片例子
class A(object):
def notFun(self): # A中没有fun函数
print('A.notFun')
class B(object):
def fun(self):
print('B.fun')
class C(object):
def fun(self):
print('C.fun')
class D(A,B):
def fun(self):
print('D.fun')
class E(B, C):
def fun(self):
print('E.fun')
class F(D, E):
def fun(self):
print('F.fun')
super(B , F()).fun() # 输出结果:C.fun
super(D , F()).fun() # 输出结果:E.fun
super(E, E()).fun() # 输出结果:B.fun
super(A , A()).fun() # 报错
分析:
由1已知:
F的mro顺序生成:F->D->A->E->B->C->object.
E的mro顺序生成:E->B->C->object.
D的mro顺序生成:D->A->B->object.
A的mro顺序生成:A->object.
B的mro顺序生成:B->object.
C的mro顺序生成:C->object.
(1)super((B , F()).fun() 即用F的mro顺序,从B之后的类开始搜索。
即在C中搜索,有fun()函数,视为找到,不再进行后续搜索,并执行C中的fun()
(2)super(D , F()).fun() 即用F的mro顺序,从D之后的类开始搜索。
即在A中搜索,没有fun()函数,继续在E中找,有fun()函数,视为找到,不再进行后续搜索,并执行E中的fun()
(3)super(E , E()).fun() 即用E的mro顺序,从E之后的类开始搜索。
即在B中搜索,有fun()函数,视为找到,不再进行后续搜索,并执行B中的fun
(4)super(A , A()).fun()
A的父类是object,没有fun函数,搜索序列也结束了,所以报父类没有这个函数的错误
②super().方法
相当于super(当前类名 , self)。这种方式只能用在类体内部,不像上面的例子可以把super拿出来。
例:
class A:
def fun(self):
print('A.fun')
class B(A):
def fun(self):
super().fun()
print('B.fun')
③ super(type_1 , type_2).方法
当super传入的两个参数都是类名是,type_2必须是type_1的子类。
例1:
super(B , E) 即 用E的mro顺序,取B之后的类的代理,即C的代理,并未对C进行实例化,所以不能调用C中的方法
例2:给例1加上实例,这一块我不是很懂,好像只要是声明了的class就可以,即便和继承树图完全没关系的类也可以,只要这个类声明了就行。
super(B , E).fun(A()) # 输出结果:C.fun
super(B , E).fun(ShiLi()) # 输出结果:C.fun,ShiLi类声明过