我是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的父母。谢谢。
答案 0 :(得分:3)
我们将仅以经典的python类为例来理解method resolution order。请记住,由于Python 3不支持经典的python类,因此MRO的概念仅适用于Python 2.7。
请考虑以下示例:
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
从输出中,我们可以看到,类D的方法正在按预期方式被首先调用。这是因为类D在继承类B和类C的类的最低层级上。现在,当类D实例中的被调用方法在类中不可用时,将首先解决哪个类的方法问题D本身和口译员必须在D的两个父类(即B级和C级可用。因此,让我们从类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都有必需的方法,解释器调用的是B类的方法,而不是C类的方法。
您可以在此处找到更多示例。 Method Resolution Order in Python (MRO)
答案 1 :(得分:0)
是因为顺序,所以如果D
是:
class D(C,B):
pass
它将输出C
,因为它得到了继承的第一个类的attr
属性。
答案 2 :(得分:0)
如果您停止考虑它,那只是直观的工作方式。到目前为止,This article看起来像是一个考古发现,仍然是对Python方法解析顺序算法的权威描述和推理。
但是,尽管其中有技术细节,但您的两个示例中发生了什么:
在第一个D,B,C,A
中,通过B的路径指示应使用A
的属性。但是A
的属性本身被C中的属性遮盖了-也就是说,C中的声明会覆盖attr
中声明的A
。因此,它是一种使用。
在第二个层次结构D,B,C,A,E
中,B优先于C,再次表明应使用A.attr
。但是,这次,A自己的属性并未被层次结构中的另一个类遮蔽-而是C.attr来自另一个“世系”-因此该语言选择了它遇到的第一个。
这是正在发生的事情的“普通英语描述”。上面链接的权威文章为此制定了正式规则:
[一个类别] C的线性化是C的和加上C的合并 父母和父母名单的线性化。 ... [给定类C(B1,...,BN):],取第一个列表的开头,即L [B1] [0] [基B1到对象的线性化(aka mro)-开头为B1- ];如果这个头不在 其他列表[其他碱基的线性化列表]的尾部,然后将其添加到线性化中 C,然后将其从合并列表中删除,否则请查看 如果这是一个不错的头,请选择下一个列表的头并接受。然后重复 直到所有班级被删除或不可能 找到好头。在这种情况下,无法构建 合并后,Python 2.3(及后续版本)将拒绝创建类C并引发
引入第二个示例,您有
D(B, C)
-B和C的线性化分别为:[B, A, object]
和[C, E, object]
,D的线性化以“ B”开头,检查是否为“ B”
在任何其他列表的尾部(并且不在[C,E,object]上),则采用B。其余列表为[A, object]
和[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
。