python 多继承 super

直接用类名调用父类方法在使用单继承的时候没问题。但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题,super 是用来解决多重继承问题的。

MRO

MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。
MRO即method resolution order,用于判断子类调用的属性来自于哪个父类。在Python2.3之前,MRO是基于深度优先算法的,自2.3开始使用C3算法,定义类时需要继承object,这样的类称为新式类,否则为旧式类

从图中可以看出,旧式类查找属性时是深度优先搜索,新式类则是广度优先搜索。
在这里插入图片描述

C3算法

C3算法最早被提出是用于Lisp的,应用在Python中是为了解决原来基于深度优先搜索算法不满足本地优先级,和单调性的问题。

  • 本地优先级:指声明时父类的顺序,比如C(A,B),如果访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类。

  • 单调性:如果在C的解析顺序中,A排在B的前面,那么在C的所有子类里,也必须满足这个顺序。



代码1

class D(object):
    def f(self):
        print('这是D')


class B(D):
    def f(self):
        print('这是B')

    def extra(self):
        print('这是extra B')


class C(D):
    def f(self):
        print('这是C')

    def extra(self):
        print('这是extra C')


class A(B, C, D):  # 声明顺序为B——>C——>D
    def f(self):
        super(A, self).f()
        print('这是A')


print(A.mro())  # 打印类的方法解析顺序表
a = A()
a.f()
a.extra()

# 输出结果为:
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]
这是B
这是A
这是extra B




代码2,调下类A的声明顺序

class D(object):
    def f(self):
        print('这是D')


class B(D):
    def f(self):
        print('这是B')

    def extral(self):
        print('这是extral B')


class C(D):
    def f(self):
        print('这是C')

    def extral(self):
        print('这是extral C')


class A(C, B, D):  # 声明顺序为C——>B——>D
    def f(self):
        super(A, self).f()
        print('这是A')


print(A.mro())  # 打印类的方法解析顺序表
a = A()
a.f()
a.extral()

# 输出结果为:
[<class '__main__.A'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.D'>, <class 'object'>]
这是C
这是A
这是extral C

小结

  1. super并不是一个函数,是一个类名,形如super(B, self)事实上调用了super类的初始化函数,
    产生了一个super对象;
  2. super类的初始化函数并没有做什么特殊的操作,只是简单记录了类类型和具体实例;
  3. super(B, self).func的调用并不是用于调用当前类的父类的func函数;
  4. Python的多继承类是通过mro的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数
    只调用一次(如果每个类都使用super);
  5. 混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一
    个父类函数被调用多次。

参考链接1
参考链接2
参考链接3

猜你喜欢

转载自blog.csdn.net/jamieblue1/article/details/89001977