在 Python 中,super() 根据方法解析顺序(MRO)处理类的继承关系

86 阅读2分钟

super()的简单要点

super() 是一个内置函数,用于调用父类的方法。它的主要作用是:

  1. 访问父类super() 可以让你轻松访问父类的方法,而不需要直接指定父类的名称。
  2. 方法解析顺序(MRO)super() 依据调用顺序来查找方法。它遵循从当前类向上查找的规则,按照类的继承顺序。
  3. 支持多继承:在多继承情况下,super() 可以帮助处理方法的调用顺序,确保每个父类的方法都能被调用。

方法解析顺序(MRO, Method Resolution Order)是 Python 中确定方法调用顺序的规则,尤其在多继承的情况下。

MRO的简单要点

  1. 定义:MRO 是一个线性序列,表示查找方法时类的顺序。
  2. 优先级:从子类向上查找直到最顶层的父类,遵循类定义的顺序。
  3. 借助 super() :使用 super() 时,会按照 MRO 查找父类的方法。
  4. 查看 MRO:可以使用 ClassName.__mro__ 或 ClassName.mro() 查看该类的 MRO。
class A: 
    pass 
class B(A): 
    pass

class C(A): 
    pass 
class D(B, C): 
    pass 
print(D.__mro__)

输出

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

class Base(object):
    def message(self, num):
        print("base message", num)
        super().message(10)


class Bar(object):
    def message(self, num):
        print("bar message",num)


class Foo(Base, Bar):
    pass


obj = Foo()
obj.message(20)

输出:

base message 20 
bar message 10

在这个例子中,你创建了一个继承自BaseBar的类Foo。这两个基类都有名为message的方法。当你创建Foo类的一个对象并调用其message方法时,Python会首先查找Foo类中定义的message方法。如果没有找到,Python会查找Foo的基类(这里是BaseBar)。在这个例子中,由于Foo类没有定义自己的message方法,所以Python会在Base类中查找这个方法并执行它。在Base类的message方法中,你调用了父类的message方法(通过super().message(10)),但由于Python会从最基类的位置开始向上查找方法,所以会执行到Bar类的message方法。因此,你会看到两行输出,首先是来自Base类的输出,然后是来自Bar类的输出。

这里有个问题: super().message(10)为什么会找到Bar类的message方法,而不是Base类的?

在 Python 中,super() 是根据方法解析顺序(MRO)查找方法的。以下是你代码中的 MRO: 1. Foo - 由于 Foo 继承自 BaseBar,MRO 为 Foo -> Base -> Bar -> object。 当你在 Base 类中调用 super().message(10) 时,super() 会查找下一个方法,即 MRO 中的下一个类,结果是 Bar 类。因此调用 Barmessage 方法。 所以,Base 中的 super().message(10) 调用的是 Bar 类的 message 方法,而不是 Base 的,因为 super() 会依据 MRO 向下查找。