设为首页收藏本站
查看: 62|回复: 0

[PHP] super在多继承中的调用细节

[复制链接]

论坛元老

Rank: 6Rank: 6

积分
34274
主题
17031
UID
1347
M币
67
贡献
17176

  • 发表于 2017-5-14 02:44:00 | 显示全部楼层 |阅读模式
    注:此处以python 3为运行环境,例子摘自《python cookbook》第8章。
    python中若子类要实现父类的初始化,主要有两种方法,第一种是直接通过父类名,第二种是利用super方法。在单继承时两者没什么区别,但在多继承时就需要注意一些细微的差距了。实例解释才是硬道理!
    1、利用父类名的情况:
    Python代码
    class Base:
    def __init__(self):
    print('Base.__init__')

    class A(Base):
    def __init__(self):
    Base.__init__(self)
    print('A.__init__')

    class B(Base):
    def __init__(self):
    Base.__init__(self)
    print('B.__init__')

    class C(A,B):
    def __init__(self):
    A.__init__(self)
    B.__init__(self)
    print('C.__init__')
    此时实例化C类会输出如下:
    Python代码
    >>> c = C()
    Base.__init__
    A.__init__
    Base.__init__
    B.__init__
    C.__init__
    >>>
    从中可看出Base类被调用了两次。这想必在很多情况下都不是我们想要的结果,所以此时可考虑用super方法。
    2、利用super的情况:
    Python代码
    class Base:
    def __init__(self):
    print('Base.__init__')

    class A(Base):
    def __init__(self):
    super().__init__()
    print('A.__init__')

    class B(Base):
    def __init__(self):
    super().__init__()
    print('B.__init__')

    class C(A,B):
    def __init__(self):
    super().__init__() # Only one call to super() here
    print('C.__init__')
    此时再实例化C类的输出为:
    Python代码
    >>> c = C()
    Base.__init__
    B.__init__
    A.__init__
    C.__init__
    >>>
    可看出Base类是不是只调用了一次啊!但很遗憾的是,这并不是促使我写这篇博客记录的原因,因为如果仔细观察的话,虽说Base类的确如预期只调用了一次,但你有没有发觉是先输出“B.__init__”而后才输出的“A.__init__”?而且为什么这样就使得Base只初始化了一次?想必你也有点懵逼了吧?其实这一切都得“怪罪”于super在多继承时的调用过程。python在实现一个类(不仅是继承)时,会产生一个方法生成解析顺序列表,该列表可通过类属性 __mro__ 查看之,如本例中是这样的:
    Python代码
    >>> C.__mro__
    (, , ,
    , )
    >>>
    所以在搜索一个属性或方法时,它就会按照这个列表遍历每个类,直到找到第一个匹配这个属性或方法的类为止。而在继承中使用super时,解释器会每遇到一次super就会在该列表上搜索下一个类,直到不再遇到super或列表遍历完为止,然后再类似递归逐层返回。因此本例中搜索过程为:C中遇到super --> 搜索列表中的下一个类,即A --> A中再次遇到super,搜索B --> B中super再现,搜索Base --> 初始化Base类,递归返回。
    为了更好的解释该过程,现在请注释掉B类的super所在行:
    Python代码
    class B(Base):
    def __init__(self):
    #super().__init__()
    print('B.__init__')

    class C(A,B):
    def __init__(self):
    super().__init__() # Only one call to super() here
    print('C.__init__')
    再次实例化C类,输出如下:
    Pythonn代码
    >>> c = C()
    B.__init__
    A.__init__
    C.__init__
    Base类不再产生输出!为什么?因为B中没了super后,就阻断了列表去搜索Base类,所以也就没有初始化Base了!
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    在我站开通SVIP可同时获得17个站点VIP资源 立即登录 立即注册
    快速回复 返回顶部 返回列表