深入理解super

在前段时间使用类的继承时,为了在子类构造函数中调用父类的构造函数,我们使用到了super方法。

使用套路如下:
这里写图片描述

super不仅仅只用在构造函数中调用父类的构造函数,普通的方法中也可以使用。

深入理解super()

看了上面的使用,我们可能会觉得super的使用很简单,无非就是获取父类,并调用父类的方法。其实,在上面的情况中,super获取到的正好是父类,但在其他情况下就不一定了。super其实和父类没有实质性的联系。

让我们写一个稍微复杂的例子,涉及到多重继承。

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

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

class B(Base):
    def __init__(self):
        print "enter B"
        super(B, self).__init__()
        print "leave B"

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

其中,Base是父类,A、B都继承自Base,C继承自A、B,它们的关系是一个典型的菱形继承,如下:

      Base
      /  \
     /    \
    A      B
     \    /
      \  /
       C

使用情况如下:
这里写图片描述

如果你认为super代表【调用父类的方法】,那么如何解释enterA的下一句不是enter Base而是enter B。原因是,super和父类没有实质性的关联。

MRO列表

事实上,对于你定义的每一个类,Python会计算出一个方法解析顺序(Method Resolution Order, MRO)列表。它代表了类继承的顺序。我们可以使用下面方法获取一个类的MRO列表。

类名.mro()

这里写图片描述

MRO列表的顺序是怎么定的呢?总的来说,一个类的MRO列表就是合并所有父类的MRO列表,并遵循以下三条原则:

  • 子类永远在父类的前面
  • 如果有多个父类,会根据它们在列表中的顺序依次被检查。
  • 如果对下一个类存在两个合法的选择,选择第一个父类(并没有理解说的是什么)

super原理

super的工作原理如下:

def super(cls, inst):
    mro = inst.__class__.mro()
    return mro[mro.index(cls)+1]

其中,cls代表类,inst代表的是实例,上面的代码做了两件事:

  • 获取inst的MRO列表
  • 查找cls在当前MRO列表中的index,并返回它的下一个类,即mro[index + 1]

所以说,在当前类中调用super返回的是MRO列表中的下一个类,并不一定是父类,也可能是同级类(多重继承的情况)
当你使用super(cls, inst)时,Python会在inst的MRO列表上搜索cls的下一个类。

至此,我们就解决了之前先输出enter B后输出enter Base的问题。
只要理解了super的工作机制,我们才会对这样的输出感到疑惑。

小结

  • 事实上,super和父类没有实质性关联。
  • super(cls, inst)获得的是当前cls(类)在MRO列表中的下一个类。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值