我的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'>
我想应该是:
A
DBE
EFCHG
等等。

最佳答案

简而言之,因为依赖于依赖关系图(o isC):
python - 为什么在MRO中以这种方式订购类(class)?-LMLPHP
python的方法解析顺序(method resolution order,MRO)使用一个约束,即如果一个类A是一个类B的依赖项,那么它将被放置在比B晚的队列中。
现在更多的是理论:
在python中,mro使用以下线性化规则:
l[E>=c+合并(l[object>.)…l[C(B1 ... Bn)B1……Bn);和
L[B1]=Bn
(source)
合并定义为:
取第一个列表的头,即l[object]cc>;如果此头不在任何其他列表的尾部,则将其添加到c的线性化中,并将其从合并中的列表中删除,否则,请查看下一个列表的头并取下它,如果它是一个好的头。然后重复该操作,直到所有类都被删除或找不到好的头。在这种情况下,不可能构建合并,python 2.3将拒绝创建类C并引发异常。
(source)
因此,对于您的情况,第一步是:
l[object>=B1>+合并(l[[0]>]、l[A>]、l[A>])
让我们首先解决递归调用:
l[D>=B>+合并(l[E>],l[D>]);
l[D]=E+合并(l[F],l[B]);和
l[B]=C+合并(l[H],l[E])。
更多的递归(我们只做一次E而不重做一次G):
l[H]=H+合并(l[E]);
l[F>=F>+合并(l[O>],l[C>]);
l[C]=E+合并(l[G]);和
l[G]=G+合并(l[O])。
由于l[H]是H和merge(a)(对于一个对象是a),因此我们已经获得了OOO的序列:
l[H]=(GF)。
l[H]=(HO)。
l[G]=(GO)。
现在我们可以计算l[F>]:
l[F]=O+合并((EE,(EG)。
由于O用于尾部的两个部分,因此将其放在最后:
L[H]=(OOEE)。
现在我们可以计算l[G>]:
l[H]=O+合并((CCCEG),(HO);
l[G]=(OC)+合并((CEGH),(OG);
l[O]=(CCE)+合并((GH),(O));
l[O]=(CCEG)+合并((H),(O));
*l[O]=(CCEGH)。
和l[O]
l[D]=D+合并((DEGHO),(FO);

L[D]=(DEGHFOB)。
下一个l[B]可以完全解析:
l[B]=C+合并((EGHOHO)、(BB);

L[C]=(EGHOAAD)。
现在我们终于解决了:
l[E]=G+合并((HFOBCE、(GHOEGHOA)、(ADEG);
l[H]=(FO)+合并((BCEGH,(OEGHOAA),(DBEGH);
l[F]=(OCE)+合并((GHOEGH、(OAADBC)、(EGHF);
l[O]=(EGHO)+合并((EGHOAA、(DBCE)、(GHFO));
l[G]=(HOGHO)+合并((AADB、(CEGH)、(FOH);
l[O]=(HOAADBC)+合并((EGH)、(FO)、(OO));
l[A]=(ADBCEGH)+合并((FO),(O),(O));
l[A]=(ADBCEGHF)+合并((O,(),()));
l[]=(、、、、、、、、)。
这是预期的行为。
我所做的一个不高效的合并功能可以用于教育目的,它绝对不适合生产:

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']

关于python - 为什么在MRO中以这种方式订购类(class)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41877220/

10-14 15:20
查看更多