我的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
D
、B
、E
E
、F
、C
、H
、G
等等。
最佳答案
简而言之,因为依赖于依赖关系图(o isC
):
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),因此我们已经获得了O
、O
和O
的序列:
l[H
]=(G
,F
)。
l[H
]=(H
,O
)。
l[G
]=(G
,O
)。
现在我们可以计算l[F
>]:
l[F
]=O
+合并((E
,E
,(E
,G
)。
由于O
用于尾部的两个部分,因此将其放在最后:
L[H
]=(O
,O
,E
,E
)。
现在我们可以计算l[G
>]:
l[H
]=O
+合并((C
,C
,C
,E
,G
),(H
,O
);
l[G
]=(O
,C
)+合并((C
,E
,G
,H
),(O
,G
);
l[O
]=(C
,C
,E
)+合并((G
,H
),(O
));
l[O
]=(C
,C
,E
,G
)+合并((H
),(O
));
*l[O
]=(C
,C
,E
,G
,H
)。
和l[O
]
l[D
]=D
+合并((D
,E
,G
,H
,O
),(F
,O
);
…
L[D
]=(D
,E
,G
,H
,F
,O
,B
)。
下一个l[B
]可以完全解析:
l[B
]=C
+合并((E
、G
、H
、O
、H
、O
)、(B
、B
);
…
L[C
]=(E
,G
,H
,O
,A
,A
,D
)。
现在我们终于解决了:
l[E
]=G
+合并((H
、F
、O
、B
、C
、E
、(G
、H
、O
、E
、G
、H
、O
、A
)、(A
、D
、E
、G
);
l[H
]=(F
,O
)+合并((B
,C
,E
,G
,H
,(O
,E
,G
,H
,O
,A
,A
),(D
,B
,E
,G
,H
);
l[F
]=(O
、C
、E
)+合并((G
、H
、O
、E
、G
、H
、(O
、A
、A
、D
、B
、C
)、(E
、G
、H
、F
);
l[O
]=(E
、G
、H
、O
)+合并((E
、G
、H
、O
、A
、A
、(D
、B
、C
、E
)、(G
、H
、F
、O
));
l[G
]=(H
、O
、G
、H
、O
)+合并((A
、A
、D
、B
、(C
、E
、G
、H
)、(F
、O
、H
);
l[O
]=(H
、O
、A
、A
、D
、B
、C
)+合并((E
、G
、H
)、(F
、O
)、(O
、O
));
l[A
]=(A
,D
,B
,C
,E
,G
,H
)+合并((F
,O
),(O
),(O
));
l[A
]=(A
,D
,B
,C
,E
,G
,H
,F
)+合并((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/