super继承执行原理

参考链接

class A(object):
    def __init__(self):
        print('enter A')
        print('leave A')


class B(A):
    def __init__(self):
        print('enter B')
        super(B, self).__init__()
        print('leave B')


class C(A):
    def __init__(self):
        print('enter C')
        super(C, self).__init__()
        print('leave C')


class D(B, C):
    def __init__(self):
        print('enter D')
        super(D, self).__init__()
        print('leave D')


d = D()
print(d.__class__.__mro__)

# debug模式下,执行的顺序
# print('enter D')
# super(D, self).__init__()
# print('enter B')
# super(B, self).__init__()
# print('enter C')
# super(C, self).__init__()
# print('enter A')
# print('leave A')
# super(D, self).__init__()
# print('leave C')
# super(B, self).__init__()
# print('leave B')
# super(D, self).__init__()
# print('leave D')

# super:
# 不要一说到 super 就想到父类!super 指的是 MRO 表中的下一个类!super 其实干的是这件事:
# def super(cls, inst):
#     mro = inst.__class__.mro() # Always the most derived class
#     return mro[mro.index(cls) + 1]
# 两个参数 cls 和 inst 分别做了两件事:
# 1. inst 负责生成 MRO 的 list
# 2. 通过 cls 定位当前 MRO 中的 index,并返回 mro[index + 1]

# 解释:
# 在 B 的 __init__() 函数中:
# super(B, self).__init__()
#
# 首先,我们获取 self.__class__.__mro__,这里的 self 是 D 的 instance:
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
#
# 然后,通过 B 定位 MRO 中的 index,并找到下一个,显然是 C,于是,调用 C 的 __init__ 打印 enter C。
#
# 1)在 MRO 中,基类永远出现在派生类后面,如果有多个基类,基类的相对顺序保持不变。
# 2)super 是针对新式类的,如果用旧式类,就应该用类名去调用方法。

此时使用的继承结构是
这里写图片描述

在这个继承中,只有一个基类A,继承分支只有一条,但当分支有多条时

class A:
    def __init__(self):
        print("Enter A")
        print("Leave A")


class B(A):
    def __init__(self):
        print("Enter B")
        super(B, self).__init__()
        print("Leave B")


class C(A):
    def __init__(self):
        print("Enter C")
        super(C, self).__init__()
        print("Leave C")


class W:
    def __init__(self):
        print("Enter W")
        print("Leave W")


class Q(W):
    def __init__(self):
        print("Enter Q")
        super(Q, self).__init__()
        print("Leave Q")


class D(Q):
    def __init__(self):
        print("Enter D")
        super(D, self).__init__()
        print("Leave D")


class E(D, B, C):
    def __init__(self):
        print("Enter E")
        super(E, self).__init__()
        print("Leave E")


E()
print(E.__mro__)

# 输出:
# Enter E
# Enter D
# Enter Q
# Enter W
# Leave W
# Leave Q
# Leave D
# Leave E
# (<class '__main__.E'>, <class '__main__.D'>, <class '__main__.Q'>, <class '__main__.W'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

#  只进入第一个分支

此时的继承图
这里写图片描述

此时继承的分支结构不是同一个终点,只会选择其中一条,按照mro顺序的开始的那条进行执行继承

就是所谓的广度优先

class A(object):
    def __init__(self):
        print("enter A")
        print("leave A")


class B(object):
    def __init__(self):
        print("enter B")
        print("leave B")


class C(A):
    def __init__(self):
        print("enter C")
        super(C, self).__init__()
        print("leave C")


class D(A):
    def __init__(self):
        print("enter D")
        super(D, self).__init__()
        print("leave D")


class E(B, C):
    def __init__(self):
        print("enter E")
        B.__init__(self)
        C.__init__(self)
        print("leave E")


class F(E, D):
    def __init__(self):
        print("enter F")
        E.__init__(self)
        D.__init__(self)
        print("leave F")


f = F()
print(F.__mro__)

# 输出结果:
# enter F
# enter E
# enter B
# leave B
# enter C
# enter D
# enter A
# leave A
# leave D
# leave C
# leave E
# enter D
# enter A
# leave A
# leave D
# leave F
# (<class '__main__.F'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)

这种情况跟第二种类似
这里写图片描述

说明:

用 super 时的输出是不同的。明显地,F 的初始化不仅完成了所有的父类的调用,而且保证了每一个父类的初始化函数只调用一次。

总结一下:

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

猜你喜欢

转载自blog.csdn.net/u013193903/article/details/80613904