Python 中的方法解析顺序

17 Mar 2025 | 5 分钟阅读

在本教程中,我们将学习方法解析顺序,也称为 MRO。它是 Python 继承中的一个重要概念。

方法解析顺序描述了类中 Python 用于在包含多重继承的类中获取适当方法的搜索路径。

引言

我们知道,被继承的类称为子类或父类,而继承的类称为子类。在多重继承中,一个类可以包含许多函数,因此使用方法解析顺序技术来搜索基类执行的顺序。

简单来说,“方法或属性在当前类中进行探索,如果当前类中不存在该方法,则搜索移至父类,依此类推”。这是一个深度优先搜索的例子。

它在多重继承中起着至关重要的作用,因为同一个方法可能存在于多个超类中。

为了更好地理解,让我们看看如何使用它。

示例 -

输出

 I am a class C

解释 -

上面的代码中存在多重继承。我们定义了三个类 A、B 和 C,这些类具有相同的名为 myname() 的方法。我们创建了一个 C 类对象。该对象调用了 C 类,而不是类,而 C 类继承了 A 类的方法。

上面的代码遵循的顺序是 **类 B -> 类 A**。这种技术称为 MRO(方法解析顺序)。

让我们通过另一个多重继承的例子来理解。

示例 -

输出

I am a class B

解释 -

在上面的代码中,我们创建了另一个 D 类,没有定义继承了 B 和 C 类的类属性。当我们调用 myname() 方法时,它会转到 D 类并搜索 myname() 函数。但是 D 类没有任何声明。因此,搜索会转移到 B 类,找到 myname() 函数并返回结果。搜索将按如下方式进行。

如果 B 类没有该方法,它将调用 C 类的方法。

在这里,我们建议您删除 B 类的方法并检查会发生什么。通过这样做,您将对方法解析如何工作有一个概念。

旧式和新式顺序

在 Python 的旧版本(2.1)中,我们只能使用旧类,但 Python(2.2 及更高版本)我们可以使用新类。默认情况下,Python 3 具有原始(新)类。新式类的第一个父类继承自 Python 的根类 'object'。让我们看下面的例子 -

示例 -

两个类的声明风格不同。在方法解析中,旧式类遵循深度优先从左到右算法(DLR),而新式类在执行多重继承时使用 C3 线性化算法。

DLR 算法

Python 在类之间实现多重继承时会创建一个类列表。当通过实例调用方法时,该列表用于确定调用哪个方法。

我们可以通过其名称假设其工作方式,方法解析将首先深度优先搜索,然后从左到右进行。下面是一个例子。

示例 -

首先,算法将在实例类中搜索调用的方法。如果找不到,它会进入第一个父类,如果仍然找不到。它会查找父类的父类。这将一直持续到继承类的末尾。

在上面的例子中,方法解析顺序将是 -

但是,A 不能重复出现,所以 -

此算法在此时会显示奇怪的行为。让我们看下面的例子。

示例 -

根据 DLR 算法,顺序将是 E、C、D、B、A。类 A 和 B 在类 C 中发生了交换,这非常含糊。这意味着该算法不保留单调性属性。

Samuele Perdoni 是第一个发现 MRO 算法之间不一致的人。

C3 线性化算法

C3 线性化算法是 DLR 算法的一个更好版本,因为它消除了不一致性。该算法有一些如下的限制。

  • 子类必须先于其父类。
  • 如果一个类继承自一个或多个类,它们将按照基类元组中指定的顺序保存。

C3 线性化算法规则

  • 方法解析顺序的结构由继承图定义。
  • 在访问了局部类的所有方法之后,用户必须访问超类。
  • 保持单调性

类方法解析方法

Python 提供了两种获取类的方法解析顺序的方法 - __mro__ 属性或 mro() 方法。借助这些方法,我们可以显示方法解析的顺序。

让我们理解下面的例子。

示例 -

输出

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

正如我们在上面的输出中所见,我们得到了方法解析顺序。C3 线性化算法就是这样对多重继承进行工作的。