Python 官方文档:入门教程 => 点击学习
目录为什么会讲 MRO?什么是 MRO注意MRO 算法什么是旧式类,新式类想深入了解 C3 算法的可以看看官网旧式类 MRO 算法新式类 MRO 算法新式 MRO 算法的问题什么是单
__mro__
可以查看方法搜索顺序实际代码
class A:
def test(self):
print("AAA-test")
class B:
def test(self):
print("BBB-test")
# 继承了三个类,B、A、还有默认继承的 object
class C(B, A):
...
# 通过类对象调用,不是实例对象!
print(C.__mro__)
# 输出结果
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
__mro__
的输出结果从左往右的顺序查找的类图
其实 MRO 是涉及一个底层算法的,下面来详细讲解一下
Python 发展到现在经历了三种算法
Python学习之新式类和旧式类讲解
https://www.python.org/download/releases/2.3/mro/
需要在 python2 环境下运行这段代码
实际代码
# 旧式类算法
class A:
def test(self):
print("CommonA")
class B(A):
pass
class C(A):
def test(self):
print("CommonC")
class D(B, C):
pass
D().test()
# python2 下的运行结果
CommonA
类图
分析
D->B->A->C->A
以上面的代码栗子来讲
D->B->A->C->A
D->B->C->A
虽然解决了旧式 MRO 算法的问题,但可能会违反单调性原则
在子类存在多继承时,子类不能改变父类的 MRO 搜索顺序,否则会导致程序发生异常
实际代码
class X(object):
pass
class Y(object):
pass
class A(X, Y):
pass
class B(Y, X):
pass
class C(A, B):
pass
深度优先遍历后的搜索顺序为:C->A->X->object->Y->object->B->Y->object->X->object
相同取后者的搜索顺序为:C->A->B->Y->X->object
分析不同类的 MRO
A->X->Y->object
A->Y->X->object
C->A->B->X->Y->object
很明显,B、C 中间的 X、Y 顺序是相反的,就是说 B 被继承时,它的搜索顺序会被改变,违反了单调性
在 python2 中运行这段代码的报错
在 python3 中运行这段代码的报错
将上面第一个栗子的代码放到 python3 中运行
class A:
def test(self):
print("CommonA")
class B(A):
pass
class C(A):
def test(self):
print("CommonC")
class D(B, C):
pass
D().test()
# 输出结果
CommonC
以上面代码为栗子,C3 会把各个类的 MRO 等价为以下等式
了解一下:头、尾
以 A 类为栗,merge() 包含的 A 成为 L[A] 的头,剩余元素(这里只有 object)称为尾
重复以上步骤直到列表为空,则算法结束;如果不能再找出可以输出的元素,则抛出异常
class B(object): pass
print(B.__mro__)
(<class '__main__.B'>, <class 'object'>)
L[B] = L[B(object)]
= B + merge(L[object])
= B + L[object]
= B object
# 计算 MRO
class B(object): pass
class C(B): pass
print(C.__mro__)
(<class '__main__.C'>, <class '__main__.B'>, <class 'object'>)
L[C] = C + merge(L[B])
= C + L[B]
= C B object
O = object
class F(O): pass
class E(O): pass
class D(O): pass
class C(D, F): pass
class B(D, E): pass
class A(B, C): pass
print(C.__mro__)
print(B.__mro__)
print(A.__mro__)
# 输出结果
(<class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>)
(<class '__main__.B'>, <class '__main__.D'>, <class '__main__.E'>, <class 'object'>)
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.F'>, <class 'object'>)
L[O] = O = object
L[D] = D + merge(L[O])
= D O
L[C] = L[C(D, F)]
= C + merge(L[D], L[F], DF)
# 从前面可知 L[D] 和 L[F] 的结果
= C + merge(DO, FO, DF)
# 因为 D 是顺序第一个并且在几个包含 D 的 list 中是 head,
# 所以这一次取 D 同时从列表中删除 D
= C + D + merge(O, FO, F)
# 因为 O 虽然是顺序第一个但在其他 list (FO)中是在尾部, 跳过
# 改为检查第二个list FO
# F 是第二个 list 和其他 list 的 head
# 取 F 同时从列表中删除 F
= C + D + F + merge(O)
= C D F O
L[B] = L[B(D, E)]
= B + merge(L[D], L[E], DE)
= B + merge(DO, EO, DE)
= B + D + merge(O, EO, E)
= B + D + E + merge(O)
= B D E O
L[A] = L[A(B,C)]
= A + merge(L[B], L[C], BC)
= A + merge( BDEO, CDFO, BC )
= A + B + merge( DEO, CDFO, C )
# D 在其他列表 CDFO 不是 head,所以跳过到下一个列表的 头元素 C
= A + B + C + merge( DEO, DFO )
= A + B + C + D + merge( EO, FO )
= A + B + C + D + E + merge( O, FO )
= A + B + C + D + E + F + merge( O )
= A B C D E F O
O = object
class F(O): pass
class E(O): pass
class D(O): pass
class C(D, F): pass
class B(E, D): pass
class A(B, C): pass
print(C.__mro__)
print(B.__mro__)
print(A.__mro__)
# 输出结果
(<class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>)
(<class '__main__.B'>, <class '__main__.E'>, <class '__main__.D'>, <class 'object'>)
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>)
L[O] = O = object
L[D] = D + merge(L[O])
= D O
L[C] = L[C(D, F)]
= C + merge(L[D], L[F], DF)
= C + merge(DO, FO, DF)
= C + D + merge(O, FO, F)
= C + D + F + merge(O)
= C D F O
L[B] = L[B(E, D)]
= B + merge(L[E], L[D], ED)
= B + merge(EO, DO, ED)
= B + E + merge(O, DO, D)
= B + E + D + merge(O)
= B E D O
L[A] = L[A(B, C)]
= A + merge(L[B], L[C], BC)
= A + merge(BEDO, CDFO, BC)
= A + B + merge(EDO, CDFO, C)
= A + B + E + merge(DO,CDFO, C)
= A + B + E + C + merge(O,DFO)
= A + B + E + C + D + merge(O, FO)
= A + B + E + C + D + F + merge(O)
= A B E C D F O
到此这篇关于Python学习之MRO方法搜索顺序的文章就介绍到这了,更多相关Python MRO方法搜索顺序内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: Python学习之MRO方法搜索顺序
本文链接: https://lsjlt.com/news/134832.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0