1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class A:
def method(self):
print("CommonA")


class B(A):
pass


class C(A):
def method(self):
print("CommonC")


class D(B, C):
pass


print("test : {}".format(D().method()))
# python2输出
CommonA
test : None

# python3输出
CommonC
test : None

import inspect
inspect.getmro(D)
# python2需要inspect模块
(<class __main__.D at 0x101ebab48>, <class __main__.B at 0x101ebaa78>, <class __main__.A at 0x101ebaa10>, <class __main__.C at 0x101ebaae0>)

print(D.__mro__)
# python3输出
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
  • python作为一个多继承的语言,方法解析顺序就变得复杂了
  • python一共提供过三个版本的MRO
    • 第一种MRO:深度遍历,也就是python2输出的结果D->B->A->C->A
    • 第二种MRO:在第一版的基础上重复出现的类只会保留最后一个D->B->C->A,核心的逻辑是,既然C是A的子类那么C中重写的方法自然优先级应该高于A中的基础方法,也就是子类优先级高于父类
    • 第三种MRO:第二种MRO思想是对的,但是存在问题,看下面的案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class X(object):
pass


class Y(object):
pass


class A(X, Y):
pass


class B(Y, X):
pass


class C(A, B):
pass

print(C.__mro__)
# 输出
TypeError: Cannot create a consistent method resolution
order (MRO) for bases X, Y
  • 如果使用第二种MRO
    • 对于 A,其搜索顺序为 A->X->Y->object
    • 对于 B,其搜索顺序为 B->Y->X->object
    • 对于 C,其搜索顺序为 C->A->B->X->Y->object
    • 对于B和C中对XY的解析顺序出现了冲突,违反了单调性
  • 第三种MRO的算法还挺复杂的,但目前python就是使用第三种MRO,也不用去记,基本还是通过第二种来做大致的判断即可,对于第二种会出现冲突的情况,第三版的MRO会报错