您的位置:

Python 中的方法解析顺序

在本教程中,我们将学习方法解析顺序,也称为 MRO。这是 Python 继承的一个基本概念。

方法解析顺序描述了类的搜索路径 Python 使用该路径在包含多重继承的类中获取合适的方法。

介绍

我们知道,被继承的类称为子类或父类,而继承的类称为子类或子类。在多重继承中,一个类可以由许多函数组成,因此使用方法解析顺序技术来搜索基类的执行顺序。

简而言之——“在当前类中探索方法或属性,如果方法不在当前类中,则搜索移动到父类,依此类推”。这是深度优先搜索的一个例子。

它在多重继承中起着重要的作用,在多重超类中可以找到相同的方法。

为了更好地理解它,让我们看看如何使用它。

示例-


class A:
    def myname(self):
        print("I am a class A")

class B(A):
    def myname(self):
        print("I am a class B")

class C(A):
    def myname(self):
        print("I am a class C") 
c = C()
print(c.myname())

输出:

 I am a class C

解释-

上述代码中存在多重继承。我们定义了三个类,分别叫做 A,B,C,这些类有相同的名字方法叫做 myname()。我们创建了一个对象类 C,这个对象调用的是类 C,而不是类,而类 C 继承了类 A 的方法。

上面代码中遵循的顺序是B 类->a 类。这种技术被称为 MRO(方法解析顺序)。

让我们理解多重继承的另一个例子。

示例-


class A:
    def myname(self):
        print(" I am a class A")
class B(A):
    def myname(self):
        print(" I am a class B")
class C(A):
    def myname(self):
        print("I am a class C")

# classes ordering
class D(B, C):
    pass    
d = D()
d.myname()

输出:

I am a class B

解释-

在上面的代码中,我们创建了另一个 D 类,但没有定义继承 B 类和 C 类的类属性。当我们调用方法 myname(),时,它会转到 D 类并搜索 myname( )函数。但是 D 类没有任何声明。因此,搜索转移到 B 类,得到 myname() 函数,并返回结果。搜索将按如下方式进行。


Class D -> Class B -> Class C -> Class A

如果 B 类没有方法,它将调用 C 类方法。

在这里,我们建议您删除 B 类方法,并检查发生了什么。通过这样做,您将了解方法解析是如何工作的。

新旧风格顺序

在旧版 Python (2.1)中,我们被限制使用旧类,但是 Python (2.2 &继续),我们可以使用新类。默认情况下,Python 3 有原始(新)类。新样式类的第一个父类继承自 Python 根“对象”类。让我们看看下面的例子-

示例-


# Old style class
class OldStyleClass:
    pass

# New style class
class NewStyleClass(object):
    pass

两个类的声明风格不同。在方法解析中,旧样式类遵循深度优先从左到右算法(DLR),而新样式类在执行多重继承时使用 C3 线性化算法。

动态链接库算法

Python 创建了一个类列表,同时实现了类之间的多重继承。该列表用于确定哪个方法必须被调用,哪个方法由实例调用。

我们可以假设按名称工作,因为方法解析将首先搜索深度,然后从左到右。下面是例子。

示例-


class A:
    pass
class B:
    pass
class C(A, B):
    pass
class D(B, A):
    pass
class E(C,D):
    pass

首先,算法将在实例类中搜索被调用的方法。如果没有找到,它就进入第一个父母,如果有也没有找到。它将查看父代的父代。这将持续到继承类结束。

在上面的示例中,方法解析顺序将是-


class D -> class B -> class A -> class C -> class A

但是,A 不能出现两次,所以-


class D -> class B -> class A -> class C ->

这个算法显示了当时的奇怪行为。让我们看看下面的例子。

示例-


class A: 
    pass

class B:
    pass

class C(A, B): 
    pass

class D(B, A): 
    pass

class E(C,D):
    pass

根据 DLR 算法,顺序会是 E,C,D,B,a,C 类中有 A & B 类的互换,很暧昧。这意味着算法没有保持单调性。

塞缪尔·佩多尼是第一个发现 MRO 算法之间不一致的人。

C3 线性化算法

C3 线性化算法是 DLR 算法的更好版本,因为它消除了不一致性。该算法有一些限制,如下所示。

  • 孩子必须先于父母。
  • 如果一个特定的类从一个或多个类继承,它们将按照基类元组中指定的顺序保存。

C3 线性化算法的规则

  • 方法解析顺序的结构由继承图定义。
  • 只有在访问了本地类的方法之后,用户才能访问超级类。
  • 保持单调性

方法解析类的方法

Python 提供了两种方法来获取类的方法解析顺序- mro 属性或 mro() 方法。在这些方法的帮助下,我们可以显示它们被解析的方法顺序。

让我们理解下面的例子。

示例-


class A:
    def myname(self):
        print(" I am a class A")
class B(A):
    def myname(self):
        print(" I am a class B")
class C(A):
    def myname(self):
        print("I am a class C")

# classes ordering
class D(B, C):
    pass    

# it prints the lookup order
print(D.__mro__)
print(C.mro())

输出:

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
[<class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

正如我们在上面的输出中看到的,我们得到了方法解析顺序的顺序。这样,C3 线性化算法适用于多重继承。