9

我对 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

等等

4

1 回答 1

22

简而言之,因为C取决于E您在依赖图中看到的 (O is object)

在此处输入图像描述

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

现在更多的理论:

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

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

L[ object] =object

(来源)

合并定义为:

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

(来源)

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

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

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

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

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

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

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

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

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

L[ E] = E+ 合并( ( G, O) , ( H, O) )

由于O两者都在尾部,所以它放在最后:

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

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

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

L[ D]

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

接下来L[ B]可以完全解决:

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

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

L[ A] = A+ 合并( ( D, E, G, H, F, O) , ( B, C, E, G, H, O) , ( E, G, H, O) ) ;
L[ A] = ( A, D) + 合并( ( E, G, H, F, O) , ( B, C, E, G, H, O) , ( E, G, H, O) ) ;
L[ A] = ( A, D, B) + 合并( ( E, G, H, F, O) , ( C, E, G, H, O) , ( E,G, H, O) ) ;
L[ A] = ( A, D, B, C) + 合并( ( E, G, H, F, O) , ( E, G, H, O) , ( E, G, H, O) ) ;
L[ A] = ( A, D, B, C, E) + 合并( ( G, H, F, O) , ( G, H, O) , ( G, H, O) ) ;
L[ A] = ( A, D, B, C, E, G) + 合并( ( H, F, O) , ( H, O) , (H, 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) , ( O) , ( O) ) ;
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']
于 2017-01-26T16:21:40.123 回答