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

时间:2017-01-26 15:40:51

标签: python python-3.x class multiple-inheritance method-resolution-order

我对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. DBE
  3. EF | CH | GH
  4. 等等

1 个答案:

答案 0 :(得分:18)

简而言之,因为 C取决于E,因为您可以在依赖关系图中看到(O是object

enter image description here

Python的方法解析顺序(MRO)使用约束,即如果类 a 是类 b 的依赖关系,则它是放在队列中的后面是 b

现在更多的理论:

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

  

L [C(B1 ... Bn)] = C +合并(L [B1] ... L [Bn],B1 ... {{1 }});和

     

L [Bn] = object

(source)

merge 定义为:

  

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

(source)

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

L [[0]] = A +合并(L [A],L [D],L [B])

让我们先解决递归调用:

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

更多递归(我们只执行一次H而不重做H):

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

由于 L [O] O合并(a)(对于一个对象 a )因此我们已经获得了OHG的序列:

L [F] =(HH
   L [O] =(GG
   L [O] =(FF

现在我们可以计算 L [O]

L [E] = E +合并({EG),(OH) )

由于O适用于尾部,因此它位于最后:

L [O] =(EEGH

现在我们可以计算 L [O]

L [C] = C +合并({CEGH),( OG));
   L [O] =(CC)+合并({EGH),({ {1}},O));
   L [G] =(OCC)+ merge((EG),({ {1}}));
   L [H] =(OOCC)+ merge((E),({ {1}}));
  * L [G] =(HOOCC)。

L [E]

L [G] = H +合并({ODDD),( EG));
  ..;
   L [H] =(OFODDE)< / em>的

下一步 L [G] 可以完全解析:

L [H] = F +合并({OBBB,{{ 1}}),(CE));
  ..;
   L [G] =(HOHOBB)< / em>的

现在我们终于可以解决了:

L [C] = E +合并({GHOA,{{ 1}},A),(DEGHFO),( BCEG));
   L [H] =(OE)+合并({GHO,{{1 },A),(ADEGHF),({ {1}},OBC));
   L [E] =(GHO)+ merge((EG,{{1 },HO),(AADBE),({ {1}},GHF));
   L [O] =(CEGH)+ merge((O,{{1 }},EGH),(OAAD),({ {1}},BCE));
   L [G] =(HFOEG)+ merge(({{1 }},HOE),(GHO),(A,{ {1}},A));
   L [D] =(BCEGHF)+合并({OGH),(OG),(HO)) ;
   L [A] =(ADBCEG,{ {1}})+合并({HF),(O),(H));
   L [O] =(HOAADB,{ {1}},C)+合并({E),(G),(H));
   L [F] =(OOOAAD,{ {1}},BC

预期的行为是什么。

我所做的效率不高的合并功能可以用于教育目的,它绝对没有针对制作进行优化:

E

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

G