为什么在MRO中以这种方式订购课程?

发布于 2021-01-29 17:50:55

我对Python MRO有此代码的问题:

class F: pass 
class G: pass 
class H: pass
class E(G,H): pass
class D(E,F): pass 
class C(E,G): pass
class B(C,H): pass
class A(D,B,E): pass

print(A.__mro__)

我得到以下输出:

(<class '__main__.A'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.G'>, <class '__main__.H'>, <class '__main__.F'>, <class 'object'>)

为什么我会<class '__main__.C'>先得到<class '__main__.E'>

我以为会是:

  1. A
  2. D,B,E
  3. E,F| C,H| G,H
    等等
关注者
0
被浏览
46
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    总之,因为C取决于E你可以在依赖-图(O是见object):

    在此处输入图片说明

    Python的方法解析顺序(MRO)的约束条件是,如果类a是类b的依赖项,则将其放置在队列中比b靠后的位置。

    现在更多的理论:

    在Python中,MRO使用以下线性化规则:

    L [ C(B1 … Bn)] = C + merge(L [ B1] … L [ Bn],B1… Bn) ; 和

    L [ object] =object

    (资源)

    而合并被定义为:

    以第一个列表的开头,即L [ B1] [0];如果此头不在任何其他列表的尾部,则将其添加到C的线性化中,然后从合并中的列表中将其删除,否则,请查看下一个列表的头并采用它,如果它是一个好头 然后重复该操作,直到所有班级都被删除,或者不可能找到好头子。在这种情况下,不可能构造合并,Python 2.3将拒绝创建类C并引发异常。

    (资源)

    因此,对于您的情况,第一步是:

    L [ A] = A+ merge(L [ D],L [ B],L [ E])
    

    让我们首先解决递归调用:

    L [ D] = D+ merge(L [ E],L [ F]) ;
    L [ B] = B+ merge(L [ C],L [ H]) ; 和
    L [ E] = E+ merge(L [ G],L [ H])。
    

    还有更多的递归(我们只做H一次,不做重做E):

    L [ F] = F+ merge(L [ O]) ;
    L [ C] = C+ merge(L [ E],L [ G]) ;
    L [ G] = G+ merge(L [ O]) ; 和
    L [ H] = H+ merge(L [ O])。
    

    由于L [ O]是O和合并的(a) (用于一个对象是一个),我们由此已经获得用于序列H,G和F:

    L [ H] =(H,O)。
    L [ G] =(G,O)。
    L [ F] =(F,O)。
    

    现在我们可以计算L [ E]:

    L [ E] = E+ merge((G,O),(H,O))。
    

    由于O两者都位于尾部,因此放在最后:

    L [ E] =( ,E,G,H)O。
    

    现在我们可以计算L [ C]:

    L [ C] = C+合并(( ,E,G,H),(O ,))GO ;
    L [ C] =( C,E)+合并(( ,G,H),(O ,))GO ;
    L [ C] =( ,,C )+合并(( ,),( ))EGHOO ;
    L [ C] =( ,C,,E )+合并(( ),())GHOO ;
    * L [ C] =( ,C,E,G,)。HO
    

    和L [ D]:

    L [ D] = D+合并(( ,E,G,H),(O ,))FO ;
    ..;
    L [ D] =( ,D,E,G,H,F)O。
    

    下一个L [ B]可以完全解析:

    L [ B] = B+合并(( ,C,E,G,H),(O ,))HO ;
    ..;
    L [ B] =( ,B,C,E,G,H)O。
    

    现在我们终于可以解决:

    L [ A] = A+合并(( ,D,E,G,H,F),(O, , ,B,C,),(E , ,, ))GHOEGHO ;
    L [ A] =( A,D)+合并(( ,E,G,H,F),(O, , ,B,C,),(E , ,, ))GHOEGHO ;
    L [ A] =( ,,A )+合并(( ,,,,),(, , ,,),( ,DBEGHFOCEGHOEG,H,O)) ;
    L [ A] =( ,A,,D )+合并(( ,,,,),(, , ,),( , ,, ))BCEGHFOEGHOEGHO ;
    L [ A] =( ,A,D,,B )+合并(( ,,,),(, , ),( , ,))CEGHFOGHOGHO ;
    L [ A] =( ,A,D,B,,C )+合并(( ,,),(, ),(EGHFOHOH,O)) ;
    L [ A] =( ,A,D,B,C,,E )+合并(( ,),(),( ))GHFOOO ;
    L [ A] =( ,A,D,B,C,E,,G )+合并(( ),(),( ))HFOOO ;
    L [ A] =( ,A,D,B,C,E,G,H,F)O。
    

    这是预期的行为。

    一个效率不高,我做了合并功能,可用于教育目的,这绝对不是为生产而优化:

    def mro_merge(*args):
        for i,arg in enumerate(args):
            if len(arg) > 0:
                head = arg[0]
                for argb in args:
                    if head in argb[1:]:
                        break
                else:
                    newargs = tuple(argb if len(argb) > 0 and argb[0] != head else argb[1:] for argb in args)
                    print('mro_merge(%s) = %s + mro_merge(%s)'%(args,head,newargs))
                    yield head
                    for x in mro_merge(*newargs):
                        yield x
                    break
    

    当您调用它时,它会生成:

    >>> list(mro_merge(('G','O'),('H','O')))
    mro_merge((('G', 'O'), ('H', 'O'))) = G + mro_merge((('O',), ('H', 'O')))
    mro_merge((('O',), ('H', 'O'))) = H + mro_merge((('O',), ('O',)))
    mro_merge((('O',), ('O',))) = O + mro_merge(((), ()))
    ['G', 'H', 'O']
    >>> list(mro_merge( ('D','E','G','H','F','O') , ('B','C','E','G','H','O') , ('E','G','H','O') ))
    mro_merge((('D', 'E', 'G', 'H', 'F', 'O'), ('B', 'C', 'E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O'))) = D + mro_merge((('E', 'G', 'H', 'F', 'O'), ('B', 'C', 'E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O')))
    mro_merge((('E', 'G', 'H', 'F', 'O'), ('B', 'C', 'E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O'))) = B + mro_merge((('E', 'G', 'H', 'F', 'O'), ('C', 'E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O')))
    mro_merge((('E', 'G', 'H', 'F', 'O'), ('C', 'E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O'))) = C + mro_merge((('E', 'G', 'H', 'F', 'O'), ('E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O')))
    mro_merge((('E', 'G', 'H', 'F', 'O'), ('E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O'))) = E + mro_merge((('G', 'H', 'F', 'O'), ('G', 'H', 'O'), ('G', 'H', 'O')))
    mro_merge((('G', 'H', 'F', 'O'), ('G', 'H', 'O'), ('G', 'H', 'O'))) = G + mro_merge((('H', 'F', 'O'), ('H', 'O'), ('H', 'O')))
    mro_merge((('H', 'F', 'O'), ('H', 'O'), ('H', 'O'))) = H + mro_merge((('F', 'O'), ('O',), ('O',)))
    mro_merge((('F', 'O'), ('O',), ('O',))) = F + mro_merge((('O',), ('O',), ('O',)))
    mro_merge((('O',), ('O',), ('O',))) = O + mro_merge(((), (), ()))
    ['D', 'B', 'C', 'E', 'G', 'H', 'F', 'O']
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看