为什么在MRO中以这种方式订购课程? [英] Why are classes being ordered this way in the MRO?

查看:91
本文介绍了为什么在MRO中以这种方式订购课程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a problem with the Python MRO For this code:

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__.E'>之前获得<class '__main__.C'>?

我认为应该是:

  1. A
  2. DBE
  3. EF | CH | GH
  1. A
  2. D,B,E
  3. E,F | C,H | G,H

以此类推

推荐答案

简而言之,因为 C依赖于E,正如您在依赖关系图中看到的那样(O为object):

In short because C depends on E as you can see in the dependency-graph (O is object):

Python的方法解析顺序(MRO)的约束条件是,如果类 a 是类 b 的依赖项,则它是放在队列中的时间比 b 晚.

Python's method resolution order (MRO) works with the constraint that if a class a is a dependency of a class b, it is placed later in the queue than b.

现在进一步了解该理论:

在Python中,MRO使用以下 linearization 规则:

In Python, the MRO works with the following linearization rule:

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

L[C(B1 ... Bn)] = C + merge(L[B1] ... L[Bn], B1 ... Bn); and

L [object] = object

(源)

合并的定义为:

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

take the head of the first list, i.e L[B1][0]; if this head is not in the tail of any of the other lists, then add it to the linearization of C and remove it from the lists in the merge, otherwise look at the head of the next list and take it, if it is a good head. Then repeat the operation until all the class are removed or it is impossible to find good heads. In this case, it is impossible to construct the merge, Python 2.3 will refuse to create the class C and will raise an exception.

(源)

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

So for your case, it is, the first step is:

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

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

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

Let us first resolve the recursive calls:

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

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

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

And more recursion (we only do H once and do not redo 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[F] = F + merge(L[O]);
L[C] = C + merge(L[E],L[G]);
L[G] = G + merge(L[O]); and
L[H] = H + merge(L[O]).

由于 L [O] O merge(a)(对于一个对象是 a ),因此,已经获得了HGF的序列:

Since L[O] is O and merge(a) (for one object is a) we thus have already obtained the sequence for H, G and F:

L [H] =(HO).
L [G] =(GO).
L [F] =(FO).

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

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

Now we can calculate L[E]:

L [E] = E + merge((GO),(HO)).

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

由于O都位于尾部,因此将其放置在最后:

Since O is for both in the tail, it is placed last:

L [E] =(EGHO).

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

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

Now we can calculate L[C]:

L [C] = C + merge((EGHO),(GO));
L [C] =(CE)+ merge((GHO),(GO)) ;
L [C] =(CEG)+ merge((HO),(O));
L [C] =(CEGH)+ merge((O),(O));
* L [C] =(CEGHO).

L[C] = C + merge( (E,G,H,O) , (G,O) );
L[C] = (C,E) + merge( (G,H,O) , (G,O) );
L[C] = (C,E,G) + merge( (H,O) , (O) );
L[C] = (C,E,G,H) + merge( (O) , (O) );
*L[C] = (C,E,G,H,O).

L [D] :

L [D] = D + merge((EGHO),(FO));
..;
L [D] =(DEGHFO).

L[D] = D + merge( (E,G,H,O) , (F,O) );
..;
L[D] = (D,E,G,H,F,O).

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

Next L[B] can be fully resolved:

L [B] = B + merge((CEGHO),(HO) );
..;
L [B] =(BCEGHO).

L[B] = B + merge( (C,E,G,H,O) , (H,O) );
..;
L[B] = (B,C,E,G,H,O).

现在我们终于可以解决:

And now we can finally resolved:

L [] = A + merge((DEGHFO),(BCEGHO),(EGHO));
L [] =(AD)+ merge((EGHFO),(BCEGHO),(EGHO));
L [] =(ADB)+ merge((EGHFO),(CEGHO),(EGHO));
L [] =(ADBC)+ merge((EGHFO ),(EGHO),(EGHO));
L [] =(ADBCE)+ merge((GHFO ),(GHO),(GHO));
L [] =(ADBCEG)+ merge((HFO ),(HO),(HO));
L [] =(ADBCEGH)+ merge((FO ),(O),(O));
L [] =(ADBCEGHF)+ merge((O ),(O),(O));
L [] =(ADBCEGHFO).

L[A] = A + merge( (D,E,G,H,F,O) , (B,C,E,G,H,O) , (E,G,H,O) );
L[A] = (A,D) + merge( (E,G,H,F,O) , (B,C,E,G,H,O) , (E,G,H,O) );
L[A] = (A,D,B) + merge( (E,G,H,F,O) , (C,E,G,H,O) , (E,G,H,O) );
L[A] = (A,D,B,C) + merge( (E,G,H,F,O) , (E,G,H,O) , (E,G,H,O) );
L[A] = (A,D,B,C,E) + merge( (G,H,F,O) , (G,H,O) , (G,H,O) );
L[A] = (A,D,B,C,E,G) + merge( (H,F,O) , (H,O) , (H,O) );
L[A] = (A,D,B,C,E,G,H) + merge( (F,O) , (O) , (O) );
L[A] = (A,D,B,C,E,G,H,F) + merge( (O) , (O) , (O) );
L[A] = (A,D,B,C,E,G,H,F,O).

这是预期的行为.

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

A not efficient merge function I've made can be used for educational purposes, it is definitely not optimized for production:

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

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

And when you call it, it generates:

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

这篇关于为什么在MRO中以这种方式订购课程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆