如果你停下来想一想,这只是直观的工作方式。本文现在看来,这只是一个考古发现,但仍然是对Python方法解析顺序算法的权威描述和推理。
但是,尽管其中有技术细节,但您的两个示例中发生的情况是:
在第一个中,D,B,C,A
,通过 B 的路径表明A
应该使用 的属性。但A
s 属性本身被 C 中的属性所遮蔽 - 也就是说,C 中的声明会覆盖attr
声明于A
。因此,它是所使用的。
在第二个层级中,D,B,C,A,E
, B 先于 C,再次表明A.attr
应该使用。然而,这一次,A 自己的属性并没有被层次结构中的另一个类所遮蔽 - 相反,C.attr 来自另一个“血统” - 因此语言选择它遇到的第一个。
这就是正在发生的事情的“简单的英语描述”。上面链接的权威文章为此奠定了正式规则:
[a class] C 的线性化是 C 的总和加上
父母的线性化和父母的列表。
...
[给定类 C(B1, ..., BN):],取第一个列表的头部,即 L[B1][0] [Base B1 到 Object 的线性化(又名 mro) - 头部是 B1 - ];如果这个头不在
任何其他列表的尾部 [其他碱基的线性化列表] ,然后将其添加到线性化
C 并将其从合并的列表中删除,否则查看
下一个列表的头部并接受它,如果它是一个好的头部。然后重复
操作直到所有类都被删除或者不可能
找到好的头脑。在这种情况下,不可能构建
合并时,Python 2.3 [及后续版本] 将拒绝创建 C 类并引发
例外。
引入你的第二个例子,你有D(B, C)
- B 和 C 的线性化为:[B, A, object]
and [C, E, object]
D 的线性化从取“B”开始,检查它不是
在任何其他列表的尾部(并且不在 [C, E, object] 上),则采用 B。剩下的名单是[A, object]
and [C, E, object]
- 然后算法选择A
它不在其他列表中,那么A
被附加到 D 的 mro 中。然后它选择object
. It is在另一个清单上。因此,该算法保持第一个列表不变,并采用 C、E 和最后的对象,对于D, B, A, C, E, object
线性化。
在你的第一个例子中,两个碱基的线性化是[B, A, object]
and [C, A, object]
当算法检查A
, it is位于第二个列表的末尾 - 所以,C
首先被选中的A
从第二个列表 - 最终的线性化是D, B, C, A, object
.