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()函数,而此时在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的MRO[D, B, C, A, object]
  d.add(2)
  print(d.n)

当我们调用 super() 时,其实质是实例化了一个 super 类。在大多数情况下,super 包含了两个非常重要的信息: 一个 MRO 以及 MRO 中的一个类。

当以方式 super(a_type, obj) 调用 super 时,MRO指的是 type(obj) 的 MRO, 而MRO中的那个类就是a_type, 同时 isinstance(obj, a_type) == True 。

当以方式 super(type1, type2) 调用 super 时,MRO 指的是 type2 的 MRO, 而MRO中的那个类就是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 on 2025-12-18 23:36  『潇洒の背影』  阅读(9)  评论(0)    收藏  举报

导航