python 中的方法解析顺序
Method resolution order in 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"。因此,我对新式 class 中的解析顺序感到困惑。有人可以澄清在 C class 之前访问 B 的父级的时间吗?谢谢
因为顺序的关系,所以如果D
是:
class D(C,B):
pass
它会输出C
,因为它得到了第一个class继承的attr
属性。
如果你停下来想一想,这只是直观的工作方式。 This article,现在看起来只是考古发现,仍然是Python方法解析顺序算法的权威描述和推理。
但是,尽管其中有技术细节,但您的两个示例中发生的情况是:
在第一个D,B,C,A
中,通过B的路径表明应该使用A
的属性。但是 A
s 属性本身被 C 中的属性遮蔽了——也就是说,C 中的声明覆盖了 A
中声明的 attr
。所以用的就是这个。
在第二层中,D,B,C,A,E
,B先于C,再次表明应该使用A.attr
。然而,这一次,A 自己的属性并没有被层次结构中的另一个 class 覆盖——而是 C.attr 来自另一个 "lineage" - 所以语言选择它遇到的第一个。
这就是正在发生的事情的 "plain english description"。上面链接的权威文章为此制定了正式规则:
the linearization of [a class] C is the sum of C plus the merge of the
linearizations of the parents and the list of the parents.
...
[given class C(B1, ..., BN):], take the head of the first list, i.e L[B1][0] [linearization (aka mro) of Base B1 up to Object - the head is B1 -]; if this head is not in
the tail of any of the other lists [linearization lists for the other bases] , then add it to the linearization
of C and remove it from the lists in the merge, otherwise look at the
head of the next list and take it, if it is a good head. Then repeat
the operation until all the class are removed or it is impossible to
find good heads. In this case, it is impossible to construct the
merge, Python 2.3 [and subsequente versions] will refuse to create the class C and will raise an
exception.
引入你的第二个例子,你有
D(B, C)
- B 和 C 的线性化是:[B, A, object]
和 [C, E, object]
并且 D 的线性化从取 "B" 开始,检查它不是
在任何其他列表的尾部(并且它不在 [C, E, object] 上),则采用 B。其余列表是 [A, object]
和 [C, E, object]
- 算法然后选择 A
它不在另一个列表中,然后 A
附加到 D 的 mro。然后选择object
。它在另一个列表中。因此,该算法保留第一个列表不变,并采用 C、E 最后是对象,以进行 D, B, A, C, E, object
线性化。
在你的第一个例子中,当算法检查A
时,两个碱基的线性化是[B, A, object]
和[C, A, object]
,它是在第二个列表的尾部 - 因此,C
比第二个列表中的 A
先被选择 - 最终的线性化是 D, B, C, A, object
。
我们将仅通过 classical python classes 的示例来理解 method resolution order。请记住,MRO 的概念仅适用于 Python 2.7,因为 Python 3 不支持 classical python classes.
考虑以下示例:
class A():
#pass
def who_am_i(self):
print("I am a A")
class B(A):
#pass
def who_am_i(self):
print("I am a B")
class C(A):
#pass
def who_am_i(self):
print("I am a C")
class D(B,C):
#pass
def who_am_i(self):
print("I am a D")
d1 = D()
d1.who_am_i()
以上程序的输出如下:
I am a D
从输出中,我们可以看到 class D 的方法按预期首先被调用。这是因为 class D 处于 classes 的最低层级,它继承了 class B 和 class C。现在关于方法的问题 [=34=当 class D 的实例中的被调用方法在 class D 本身中不可用并且解释器必须爬升一级时,首先会解决 ] 父级 class D的es,即class B 和 class C 可用。所以,让我们从 class D 中删除这个方法,看看解释器做了什么。
class A():
#pass
def who_am_i(self):
print("I am a A")
class B(A):
#pass
def who_am_i(self):
print("I am a B")
class C(A):
#pass
def who_am_i(self):
print("I am a C")
class D(B,C):
pass
d1 = D()
d1.who_am_i()
以上程序的输出如下:
I am a B
即使 B 和 C 都有所需的方法,解释器调用了 class B 的方法而不是 class C 的方法。
您可以在此处找到更多示例。 Method Resolution Order in Python (MRO)
我是 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"。因此,我对新式 class 中的解析顺序感到困惑。有人可以澄清在 C class 之前访问 B 的父级的时间吗?谢谢
因为顺序的关系,所以如果D
是:
class D(C,B):
pass
它会输出C
,因为它得到了第一个class继承的attr
属性。
如果你停下来想一想,这只是直观的工作方式。 This article,现在看起来只是考古发现,仍然是Python方法解析顺序算法的权威描述和推理。
但是,尽管其中有技术细节,但您的两个示例中发生的情况是:
在第一个D,B,C,A
中,通过B的路径表明应该使用A
的属性。但是 A
s 属性本身被 C 中的属性遮蔽了——也就是说,C 中的声明覆盖了 A
中声明的 attr
。所以用的就是这个。
在第二层中,D,B,C,A,E
,B先于C,再次表明应该使用A.attr
。然而,这一次,A 自己的属性并没有被层次结构中的另一个 class 覆盖——而是 C.attr 来自另一个 "lineage" - 所以语言选择它遇到的第一个。
这就是正在发生的事情的 "plain english description"。上面链接的权威文章为此制定了正式规则:
the linearization of [a class] C is the sum of C plus the merge of the linearizations of the parents and the list of the parents. ... [given class C(B1, ..., BN):], take the head of the first list, i.e L[B1][0] [linearization (aka mro) of Base B1 up to Object - the head is B1 -]; if this head is not in the tail of any of the other lists [linearization lists for the other bases] , then add it to the linearization of C and remove it from the lists in the merge, otherwise look at the head of the next list and take it, if it is a good head. Then repeat the operation until all the class are removed or it is impossible to find good heads. In this case, it is impossible to construct the merge, Python 2.3 [and subsequente versions] will refuse to create the class C and will raise an exception.
引入你的第二个例子,你有
D(B, C)
- B 和 C 的线性化是:[B, A, object]
和 [C, E, object]
并且 D 的线性化从取 "B" 开始,检查它不是
在任何其他列表的尾部(并且它不在 [C, E, object] 上),则采用 B。其余列表是 [A, object]
和 [C, E, object]
- 算法然后选择 A
它不在另一个列表中,然后 A
附加到 D 的 mro。然后选择object
。它在另一个列表中。因此,该算法保留第一个列表不变,并采用 C、E 最后是对象,以进行 D, B, A, C, E, object
线性化。
在你的第一个例子中,当算法检查A
时,两个碱基的线性化是[B, A, object]
和[C, A, object]
,它是在第二个列表的尾部 - 因此,C
比第二个列表中的 A
先被选择 - 最终的线性化是 D, B, C, A, object
。
我们将仅通过 classical python classes 的示例来理解 method resolution order。请记住,MRO 的概念仅适用于 Python 2.7,因为 Python 3 不支持 classical python classes.
考虑以下示例:
class A():
#pass
def who_am_i(self):
print("I am a A")
class B(A):
#pass
def who_am_i(self):
print("I am a B")
class C(A):
#pass
def who_am_i(self):
print("I am a C")
class D(B,C):
#pass
def who_am_i(self):
print("I am a D")
d1 = D()
d1.who_am_i()
以上程序的输出如下:
I am a D
从输出中,我们可以看到 class D 的方法按预期首先被调用。这是因为 class D 处于 classes 的最低层级,它继承了 class B 和 class C。现在关于方法的问题 [=34=当 class D 的实例中的被调用方法在 class D 本身中不可用并且解释器必须爬升一级时,首先会解决 ] 父级 class D的es,即class B 和 class C 可用。所以,让我们从 class D 中删除这个方法,看看解释器做了什么。
class A():
#pass
def who_am_i(self):
print("I am a A")
class B(A):
#pass
def who_am_i(self):
print("I am a B")
class C(A):
#pass
def who_am_i(self):
print("I am a C")
class D(B,C):
pass
d1 = D()
d1.who_am_i()
以上程序的输出如下:
I am a B
即使 B 和 C 都有所需的方法,解释器调用了 class B 的方法而不是 class C 的方法。
您可以在此处找到更多示例。 Method Resolution Order in Python (MRO)