python - 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 的父母。谢谢。
解决方案
如果你停下来想一想,这只是直观的工作方式。这篇到现在还只是考古发现的文章,依然是Python方法解析顺序算法的权威描述和推理。
但是,尽管那里有技术细节,但在您的两个示例中发生的情况是:
在第一个中,D,B,C,A
通过 B 的路径表示A
应该使用 的属性。但是A
s 属性本身被 C 中的属性所掩盖——也就是说,C 中的声明覆盖了attr
in 中的声明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
。
推荐阅读
- ajax - 反应显示来自 Ajax 请求的项目列表
- ios - NEHotspotConfiguration 中的 joinOnce 做了什么?
- orientdb - 如果一个类不从 E 或 V 继承,它是否仍可用于 OrientDB 2.2 中的图形查询?
- sql-server - 以 1 分钟间隔获取平均值和最大值 T-SQL
- excel - 如何在 VBA 中处理一个大的 .csv 文件
- r - ggboxplot - 图表的顶部没有被绘制
- node.js - Node.js Sequelize.js Categories.forEach 不是函数
- vb.net - 如何在 VB.NET 中的每个文本框行之后添加文本
- python - Python:将 8 字节 IEEE754 数字转换为浮点数
- arrays - Excel VBA Total Column in 2D array Ubound