Python继承中的方法解析顺序
方法解析顺序:
方法解析顺序(MRO)它表示编程语言解析方法或属性的方式。 Python支持从其他类继承的类。被继承的类称为父类或超类,而继承的类称为子类或子类。在Python中,方法解析顺序定义了执行方法时搜索基类的顺序。首先,在类中搜索方法或属性,然后按照我们在继承时指定的顺序进行搜索。此顺序也称为类的线性化,而一组规则称为 MRO(方法解析顺序)。从另一个类继承时,解释器需要一种方法来解析通过实例调用的方法。因此我们需要方法解析顺序。例如
Python3
# Python program showing
# how MRO works
class A:
def rk(self):
print(" In class A")
class B(A):
def rk(self):
print(" In class B")
r = B()
r.rk()
Python3
# Python program showing
# how MRO works
class A:
def rk(self):
print(" In class A")
class B(A):
def rk(self):
print(" In class B")
class C(A):
def rk(self):
print("In class C")
# classes ordering
class D(B, C):
pass
r = D()
r.rk()
Python3
# Old style class
class OldStyleClass:
pass
# New style class
class NewStyleClass(object):
pass
Python3
class A:
pass
class B:
pass
class C(A, B):
pass
class D(B, A):
pass
class E(C,D):
pass
Python3
# Python program to show the order
# in which methods are resolved
class A:
def rk(self):
print(" In class A")
class B:
def rk(self):
print(" In class B")
# classes ordering
class C(A, B):
def __init__(self):
print("Constructor C")
r = C()
# it prints the lookup order
print(C.__mro__)
print(C.mro())
输出:
In class B
在上面的示例中,调用的方法来自 B 类而不是 A 类,这是由于方法解析顺序(MRO)。
上面代码中的顺序是-B类->A类
在多重继承中,方法是根据继承类时指定的顺序执行的。对于支持单继承的语言,方法解析顺序并不重要,但支持多继承的语言的方法解析顺序却起着非常关键的作用。让我们看另一个例子来深入理解方法解析顺序:
Python3
# Python program showing
# how MRO works
class A:
def rk(self):
print(" In class A")
class B(A):
def rk(self):
print(" In class B")
class C(A):
def rk(self):
print("In class C")
# classes ordering
class D(B, C):
pass
r = D()
r.rk()
输出:
In class B
在上面的例子中,我们使用了多重继承,它也被称为Diamond 继承,它看起来如下:
Python遵循深度优先查找顺序,因此最终从类A调用方法。按照方法解析顺序,查找顺序如下。
D 类 -> B 类 -> C 类 -> A 类
Python遵循深度优先顺序来解析方法和属性。所以在上面的例子中,它执行了 B 类中的方法。新旧样式顺序:
在旧版本的Python(2.1) 中,我们必须使用旧样式的类,但在Python(3.x 和 2.2) 中,我们只能使用新的类。新样式类的第一个父类继承自Python根“对象”类。
Python3
# Old style class
class OldStyleClass:
pass
# New style class
class NewStyleClass(object):
pass
两种声明风格中的方法解析顺序(MRO)不同。旧样式类使用DLR 或深度优先从左到右算法,而新样式类在进行多重继承时使用C3 线性化算法进行方法解析。 DLR 算法
在实现多重继承期间, Python会构建一个要搜索的类列表,因为它需要解析在实例调用一个方法时必须调用哪个方法。顾名思义,方法解析顺序将首先搜索深度,然后从左到右。例如
Python3
class A:
pass
class B:
pass
class C(A, B):
pass
class D(B, A):
pass
class E(C,D):
pass
在上面的示例算法中,首先查看被调用方法的实例类。如果不存在,则查看第一个父项,如果该父项也不存在,则查看父项的父项。这一直持续到类的深度结束,最后,直到继承类的结束。所以,我们最后一个例子中的分辨率顺序是 D、B、A、C、A。但是,A 不能出现两次,因此顺序是 D、B、A、C。但是这个算法以不同的方式变化,并且在不同的时间表现出不同的行为。所以 Samuele Pedroni 首先发现了一个不一致的地方,并引入了 C3 线性化算法。 C3 线性化算法:
C3 线性化算法是一种使用新型类的算法。它用于消除由 DLR 算法创建的不一致。它有一定的局限性,它们是:
- 孩子先于父母
- 如果一个类继承自多个类,它们将按照基类元组中指定的顺序保存。
C3 线性化算法适用于三个规则:
- 继承图决定了方法解析顺序的结构。
- 只有在访问了本地类的方法后,用户才需要访问超类。
- 单调性
类的方法解析顺序(MRO)的方法:
要获取类的方法解析顺序,我们可以使用 __mro__ 属性或 mro() 方法。通过使用这些方法,我们可以显示解决方法的顺序。例如
Python3
# Python program to show the order
# in which methods are resolved
class A:
def rk(self):
print(" In class A")
class B:
def rk(self):
print(" In class B")
# classes ordering
class C(A, B):
def __init__(self):
print("Constructor C")
r = C()
# it prints the lookup order
print(C.__mro__)
print(C.mro())
输出:
Constructor C
(, , , )
[, , , ]