我正在阅读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新手,所以我想我错过了什么?
答案 0 :(得分:1)
问题是,无论是在Python 2.2,2.3还是更高版本中,这些都是新式的类。这里有 3 方法解析方案,而不是2:
方案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新式类规则给出相同答案的情况。