首页 > 解决方案 > python中的方法解析顺序

问题描述

我是 python 新手。我正在使用python 2.7。我正在通过一个小片段进行方法顺序解析,如下所示:

class A(object):
    attr = 'A'

class B(A):
    pass

class C(A):
    attr = 'C'

class D(B,C):
    pass

x = D()
print x.attr

分辨率的顺序是 x,D,B,C,A,因此输出将是 C。按照上面的例子,我对代码做了一个小的改动。

class A(object):
    attr = 'A'

class E(object):
    attr = 'E'

class B(A):
    pass

class C(E):
    attr = 'C'

class D(B,C):
    pass

x = D()
print x.attr

按照我之前的示例,我预计顺序是 x、D、B、C、A、E。令我惊讶的是,输出是“A”。因此,我对新式课程的解决顺序感到困惑。有人可以澄清在 C 课之前何时访问 B 的父母。谢谢。

标签: pythonmethod-resolution-orderpython-mro

解决方案


如果你停下来想一想,这只是直观的工作方式。这篇到现在还只是考古发现的文章,依然是Python方法解析顺序算法的权威描述和推理。

但是,尽管那里有技术细节,但在您的两个示例中发生的情况是:

在第一个中,D,B,C,A通过 B 的路径表示A应该使用 的属性。但是As 属性本身被 C 中的属性所掩盖——也就是说,C 中的声明覆盖了attrin 中的声明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]并且[C, E, object]D 的线性化从采用“B”开始,检查它不在任何其他列表的尾部(并且它不在 [C, E, object]),然后取 B。剩下的列表是[A, object]and [C, E, object]- 然后算法选择A它不在另一个列表中,然后A附加到 D 的 mro。然后选择object。它另一个列表中。因此该算法保持第一个列表不变,并采用 C、E 和最后的对象进行D, B, A, C, E, object线性化。

在您的第一个示例中,两个碱基的线性化是,[B, A, object]并且[C, A, object]当算法检查 时A,它位于第二个列表的尾部 - 因此,C首先A从第二个列表中挑选 - 最终的线性化是D, B, C, A, object


推荐阅读