CodeGym /Java 课程 /Python SELF ZH /方法解析顺序 (MRO)

方法解析顺序 (MRO)

Python SELF ZH
第 16 级 , 课程 5
可用

11.1 方法解析顺序

方法解析顺序(Method Resolution Order, MRO)定义了 Python 在类层次结构中寻找方法和属性的顺序。在多重继承中,这尤其重要,因为一个类可能会从多个父类中继承属性和方法。

简单来说,有一个严格固定的顺序(或者说是算法),Python 按照这个算法遍历类继承树。这个算法确保了正确的方法查找顺序,大致如下:

C3线性化算法

C3线性化算法通过结合以下内容确定 MRO:

  • 类本身。
  • 父类按照声明顺序的列表。
  • 同样顺序的父类的 MRO

C3线性化算法规则

  • 保持方法的局部顺序:如果类 A 被声明在类 B 之前,那么类 A 的所有方法都应在类 B 的方法之前查看。
  • 维持父类的顺序:如果类 A 是类 B 的父类,那么类 A 的所有方法都应在类 B 的方法之前查看。
  • 考虑继承的顺序:如果类 C 是两个或多个类的父类,类 C 的方法顺序应在这些类的 MRO 中保持不变。

算法步骤:

步骤 1. 从类本身开始:

总是从调用方法的类本身开始。

步骤 2. 添加基类按照它们声明的顺序:

在当前类之后,按照继承时指定的顺序检查基类。

步骤 3. 遍历父类:

在那里寻找字段和方法。

步骤 4. 结合父类的 MRO:

如果同一个基类通过多个路径继承,它只会被检查一次,并且是按照正确的顺序(其它所有时候会被跳过)。

对于已经了解“算法与数据结构”的人来说,这是一种深度优先搜索,而不是广度优先搜索。

11.2 检查 MRO

在 Python 中,可以使用属性 __mro__ 或函数 mro() 检查类的方法和字段的遍历顺序。

例子:


class A:
    def method(self):
        print("A")
        
class B(A):
    def method(self):
        print("B")
        
class C(A):
    def method(self):
        print("C")
        
class D(B, C):
    def method(self):
        print("D")
        

# 检查 MRO
print(D.__mro__)
        

输出将是:


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

这显示了 Python 将寻找方法和属性的顺序:

  • D:Python 首先在类 D 中查找方法。
  • B:然后 Python 查找类 B(第一个父类)中的方法。
  • C:如果类 B 中没有找到方法,Python 将在类 C(第二个父类)中查找方法。
  • A:如果在类 BC 中都没有找到方法,Python 将在类 A 中查找方法。
  • object:最后,Python 在基类 object 中查找方法。

11.3 使用 super() 与 MRO

函数 super() 遵循 MRO 来按正确的顺序调用父类的方法。来看一下如何使用 super()

class A:
    def method(self):
        print("A")
        super().method()
        
class B(A):
    def method(self):
        print("B")
        super().method()
        
class C(A):
    def method(self):
        print("C")
        super().method()
        
class D(B, C):
    def method(self):
        print("D")
        super().method()
        
        
d = D()
d.method()
        

输出将是:


D
B
C
A
        

遍历顺序 (MRO)

1. 调用类 D 的方法 method

  • Python 首先在类 D 中查找到方法。
  • 执行方法 D.method() 并打印 "D"
  • 然后调用 super().method(),它按照 MRO 调用下一个方法。

2. 调用类 B 的方法 method

  • 根据 MRO,紧随 D 之后的类是 B
  • 执行方法 B.method() 并打印 "B"
  • 然后调用 super().method(),它按照 MRO 调用下一个方法。

3. 调用类 C 的方法 method

  • MRO 中紧随 B 之后的类是 C
  • 执行方法 C.method() 并打印 "C"
  • 然后调用 super().method(),它按照 MRO 调用下一个方法。

4. 调用类 A 的方法 method

  • MRO 中紧随 C 之后的类是 A
  • 执行方法 A.method() 并打印 "A"
  • 然后调用 super().method(),但由于 A 没有父类的 method(除了 object),调用将结束而没有进一步的操作。
1
Опрос
继承,  16 уровень,  5 лекция
недоступен
继承
继承
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION