python中super()方法的理解

python中对象方法的定义很怪异,第一个参数一般都命名为self(相当于其它语言的this),用于传递对象本身,

有时候还会有一个参数cls(相当于类名,当直接调用类方法的时候使用)。

python2中super()的用法:

     super(class,self).__init__()

python3中super()的用法:

     super().__init__()


 

在类的继承里面super()非常常用, 它解决了子类调用父类方法的一些问题, 父类多次被调用时只执行一次。

def super(cls, inst):

      mro = inst.__class__.mro()

      return mro[mro.index(cls) + 1]

当使用 super(cls, inst) 时,Python 会在 inst 的类的 MRO 列表上搜索 cls 的下一个类。

而查看inst类的的MRO列表的方法就是:

类.mro()   或  类.__mro__ 或 inst.__class__.mro()

例如:当C是一个类的时候,获得一个类的MRO的方法是

C.mro() 或  C.__mro__  或 C().__class__.mro()

 

执行过程:

  当执行生成D的inst对象的时候,先执行Enter D

这个时候D类的MRO列表为[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

当执行super(D,self) 就是在self对象的类的MRO列表中查找D的下一个父类。这个self是D类的实例对象inst。

而D类中的MRO列表中D的下一个父类是B。

例如:

1、super单继承的时候:

 

class A:
def __init__(self):
self.n = 2
def add(self, m):
print('self is {0} @A.add'.format(self))
self.n += m

class B(A):
def __init__(self):
self.n = 3
def add(self, m):
print('self is {0} @B.add'.format(self))
super().add(m)
self.n += 3
b = B()
b.add(2)
print(b.n)

 

结果是什么呢?

 

为什么是8?

执行b.add(2)的时候,执行A中的add()函数,执行的时候这个时候的self是b这个实例,所以这个self.n是3

所以执行3+2=5

然后执行super的下一句5+3=8。

2、super多继承的时候

 

#super的多继承
class A:
def __init__(self):
self.n = 2
def add(self, m):
print('self is {0} @A.add'.format(self))
self.n += m
class B(A):
def __init__(self):
self.n = 3
def add(self, m):
print('self is {0} @B.add'.format(self))
super().add(m)
self.n += 3
class C(A):
def __init__(self):
self.n = 4
def add(self, m):
print('self is {0} @C.add'.format(self))
super().add(m)
self.n += 4
class D(B, C):
def __init__(self):
self.n = 5
def add(self, m):
print('self is {0} @D.add'.format(self))
super().add(m)
self.n += 5
d = D()
d.add(2)
print(d.n)

 

 这个结果是什么呢?

我认为是5+B.add+C.add+A.add+5=5+3+4+2+5=19

看下输出的结果:

 

执行过程是什么样的呢?

详细的代码分析如下:

 

class A:
def __init__(self):
self.n = 2
def add(self, m):
print('self is {0} @A.add'.format(self))
self.n += m#第4步执行,A.add(2),这个时候self=b,n=5,即n=5+2=7
class B(A):
def __init__(self):
self.n = 3
def add(self, m):
print('self is {0} @B.add'.format(self))
super().add(m)#第2步执行,相当于super(B,d),在d的MRO[D,B,C,A,Object]中B的下一个C.add(2),这个时候self=b,n=5
self.n += 3 #第6步执行,n=11+3=14
class C(A):
def __init__(self):
self.n = 4
def add(self, m):
print('self is {0} @C.add'.format(self))
super().add(m)#第3步执行,相当于super(C,d),在d的MRO[D,B,C,A,Object]中C的下一个A.add(2),这个时候self=b,n=5
self.n += 4 #第5步执行,n=7+4=11
class D(B, C):
def __init__(self):
self.n = 5
def add(self, m):
print('self is {0} @D.add'.format(self))
super().add(m)#第1步执行相当于super(D,d)这个时候就会返回在d的MRO[D,B,C,A,Object]中D的下一个类B,执行B.add(2)
self.n += 5 #第7步执行,n=14+5=19
d = D()
print(d.__class__.mro())#[D, B, C, A,object]
d.add(2)
print(d.n)

 当我们调用 super() 的时候,实际上是实例化了一个 super 类

在大多数情况下, super 包含了两个非常重要的信息: 一个 MRO 以及 MRO 中的一个类。当以如下方式调用 super 时:

super(a_type, obj)

MRO 指的是 type(obj) 的 MRO, MRO 中的那个类就是 a_type , 同时 isinstance(obj, a_type) == True 。

当这样调用时:

super(type1, type2)

MRO 指的是 type2 的 MROMRO 中的那个类就是 type1 ,同时 issubclass(type2, type1) == True 。

那么, super() 实际上做了啥呢?简单来说就是:提供一个 MRO 以及一个 MRO 中的类 C , super() 将返回一个从 MRO 中 C 之后的类中查找方法的对象。

也就是说,查找方式时不是像常规方法一样从所有的 MRO 类中查找

举个例子, 有个 MRO:

[A, B, C, D, E, object]

下面的调用:

super(C, A).add()

super 只会从 C 之后查找,即: 只会在 D 或 E 或 object 中查找 add 方法

 

posted @ 2020-05-27 18:32  一日学一日功  阅读(5020)  评论(0编辑  收藏  举报