类的继承


# 类的继承

Python 支持多父类的继承机制,所以需要注意圆括号中基类的顺序,若是基类中有相同的方法名,并且在子类使用时未指定,Python 会从左至右搜索基类中是否包含该方法。一旦查找到则直接调用,后面不再继续查找。

object 是 Python 为所有对象提供的父类,默认提供一些内置的属性、方法;可以使用 dir 方法查看。

dir(object)
1

# 新式类和旧式类

# 新式类

  • object 为父类的类,推荐使用
  • 在 Python 3.x 中定义类时,如果没有指定父类,会默认使用 object 作为该类的父类
  • 所以 Python 3.x 中定义的类都是新式类

# 旧式类

  • 不以 object 为父类的类,不推荐使用
  • 在 Python 2.x 中定义类,如果没有指定父类,不会使用 object 作为基类

# 区别

在多继承时,会影响到方法搜索顺序 MOR。

# 建议使用新式类

为了保证编写的代码能够同时在 Python2.x 和 Python 3.x 中运行,建议在定义类时,如果没有父类,也统一继承 object

class 类名(object):
    pass
1
2

本文接下来讲的知识点也将会围绕新式类的继承机制展开。

# 继承机制

Python3 的继承机制(新式类)不同于 Python2(旧式类)。其核心原则是下面两条:

  • 子类在调用某个方法或变量的时候,首先在自己内部查找,如果没有找到,则开始根据继承机制在父类里查找。
  • 根据父类定义中的顺序,以深度优先的方式逐一查找父类。

# 第一个例子

设想有下面的继承关系:

class A(B, E):
    pass
1
2
  • A 继承 B 和 E
    • B 继承 C,C 继承 D
    • E 继承 F,F 继承 G

如下图所示:

ABECFDG

(继承关系 - 第一个例子)

在这种继承结构关系中,子类在调用某个方法或变量的时候,搜索顺序是这样的(按下图中红色箭头路径指向):

ABECFDG123456

(第一个例子的搜索顺序)

# 第二个例子

如果继承结构是这样的:类 D 和类 G 又同时继承了类 H,如下图所示:

ABECFDGH

(继承关系 - 第二个例子)

此时的搜索顺序是这样的(按下图中红色箭头路径指向):

ABECFDG123456H7

(第二个例子的搜索顺序)

至于其它更错综复杂的继承情况,其实都能划分成上面两种情况。

# MRO 算法

  • MRO(method resolution order)方法搜索顺序
  • 对于单继承来说,MRO 很简单,从当前类开始,逐个搜索它的父类有没有对应的属性、方法
  • 所以 MRO 更多用在多继承时判断方法、属性的调用路径
  • Python 中针对类提供了一个内置属性 __mro__ 可以查看方法搜索顺序
class A:
    def test(self):
        print("AAA-test")


class B:
    def test(self):
        print("BBB-test")

# 继承了三个类,B、A、还有默认继承的 object
class C(B, A):
    ...


# 通过类对象调用,不是实例对象!
print(C.__mro__)


# 输出结果
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

在搜索方法时,是按照 __mro__ 的输出结果从左往右的顺序查找的。

(完)