对于旧式和新式,此类层次结构的MRO是否相同?

时间:2018-04-02 16:01:08

标签: python multiple-inheritance method-resolution-order

我正在阅读Python 2.3 MRO文章,其中给出了以下类层次结构:

>>> O = object
>>> class F(O): pass
>>> class E(O): pass
>>> class D(O): pass
>>> class C(D,F): pass
>>> class B(E,D): pass
>>> class A(B,C): pass

                           6
                          ---
Level 3                  | O |
                       /  ---  \
                      /    |    \
                     /     |     \
                    /      |      \
                  ---     ---    ---
Level 2        2 | E | 4 | D |  | F | 5
                  ---     ---    ---
                   \      / \     /
                    \    /   \   /
                     \  /     \ /
                      ---     ---
Level 1            1 | B |   | C | 3
                      ---     ---
                       \       /
                        \     /
                          ---
Level 0                0 | A |
                          ---

在其后的段落中,以下引用让我困惑:

  

懒惰的程序员可以直接从Python 2.2获取MRO   在这种情况下,它与Python 2.3线性化一致。

>>> A.mro()
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>,
<class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>,
<type 'object'>)

我之所以感到困惑的原因是在文章的前面说过:

  

经典类维持旧的方法解析顺序,深度   先从左到右。

问题:如果旧式MRO是深度优先的,从左到右,那么上述类层次结构的旧式MRO应该是不同的,即ABEODOCDOFO。因此,“懒惰程序员”无法直接从Python 2.2获取其MRO。是吗?

例如,在以下代码段上(不要在Python 3.x上运行它):

class O: 
    x = 'o'
class F(O): pass
class E(O): pass
class D(O): pass
class C(D,F): 
    x = 'c'
class B(E,D): pass
class A(B,C): pass

print A.x

如果旧式MRO与新式MRO(即ABEC等)相同,我希望它能打印c。但是,它打印o(即,它是ABEO等)。

或者在这里:

class O: pass
class F(O): pass
class E(O): pass
class D(O):
    x = 'd'
class C(D,F): 
    x = 'c'
class B(E,D): pass
class A(B,C): pass

print A.x

如果旧式MRO与新式MRO(即ABEC等)相同,我希望它能打印c。但是,它打印d(即,它是ABEOD等)。

我是Python新手,所以我想我错过了什么?

3 个答案:

答案 0 :(得分:1)

问题是,无论是在Python 2.2,2.3还是更高版本中,这些都是新式的类。这里有 3 方法解析方案,而不是2:

  1. 经典类方法解析。
  2. Python 2.2新式类方法解析。
  3. Python 2.3+ C3线性化。
  4. 方案2和3将为给定的示例生成相同的MRO。

    如果你想看到(现在几乎完全无关的)Python 2.2方法解析方案,最完整的文档可能是来自Guido旧的Python历史博客的working fiddle。还有一个用于Python 2.2的a blog post文档,其中主要描述了它,但未提及特殊情况。

答案 1 :(得分:1)

the blog post from Guido(2010年6月),特别是这个重要的细节:

  

MRO的计算正式记录为使用如前所述的深度优先从左到右的遍历。如果在此搜索中重复了任何类,则除了最后一次出现的所有类都将从MRO列表中删除。

所以你有ABEODOCDOFO,是的,但早先的O被删除了!

&#34;正式记录&#34;声称Guido写的不是来自您问题中链接的2.3 MRO页面,而是来自较旧的2.2 MRO page,您将在其中找到:

  

使用经典查找规则,构造将要搜索的类列表,包括重复项。现在,对于列表中多次出现的每个类,删除除最后一个之外的所有匹配项。

答案 2 :(得分:0)

旧式课程没有内置mro方法;只有新式的课程。

另外,请注意,实际示例包含O = object,而不是class O: pass,这些新类型。

这个例子是读者练习的一部分。

所以这一段只是说一个懒惰的程序员不想为这个例子练习,而且还没有访问2.3解释器,可以将这段代码粘贴到2.2中。解释器并调用A.mro()并得到答案 - 因为这种情况恰好是2.2和2.3新式类规则给出相同答案的情况。

相比之下,一个非懒惰的程序员会想要知道他们什么时候做,也不会给出相同的答案,而不仅仅是指他们有时会这样做的事实。