亲宝软件园·资讯

展开

Python MRO方法搜索顺序 Python学习之MRO方法搜索顺序

小菠萝测试笔记 人气:0
想了解Python学习之MRO方法搜索顺序的相关内容吗,小菠萝测试笔记在本文为您仔细讲解Python MRO方法搜索顺序的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:Python,MRO,Python,方法搜索顺序,下面大家一起来学习吧。

为什么会讲 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学习之新式类和旧式类讲解

想深入了解 C3 算法的可以看看官网

https://www.python.org/download/releases/2.3/mro/

旧式类 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

类图

分析

新式类 MRO 算法

以上面的代码栗子来讲

新式 MRO 算法的问题

虽然解决了旧式 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

很明显,B、C 中间的 X、Y 顺序是相反的,就是说 B 被继承时,它的搜索顺序会被改变,违反了单调性

在 python2 中运行这段代码的报错

在 python3 中运行这段代码的报错

C3 MRO 算法

将上面第一个栗子的代码放到 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 算法

以上面代码为栗子,C3 会把各个类的 MRO 等价为以下等式

了解一下:头、尾

以 A 类为栗,merge() 包含的 A 成为 L[A] 的头,剩余元素(这里只有 object)称为尾

merge 的运算方式

重复以上步骤直到列表为空,则算法结束;如果不能再找出可以输出的元素,则抛出异常

简单类 MRO 的计算栗子

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 的计算栗子

# 计算 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

多继承MRO 的计算栗子

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

多继承MRO 的计算栗子二

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

加载全部内容

相关教程
猜你喜欢
用户评论