🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 7.5 【基础】类的继承(Inheritance) 类的继承,跟人类繁衍的关系相似。 被继承的类称为基类(也叫做父类),继承而得的类叫派生类(也叫子类),这种关系就像人类的父子关系。 继承最大的好处是子类获得了父类的全部变量和方法的同时,又可以根据需要进行修改、拓展。 继承的语法结构是 ```python class 子类(父类): ``` ## 1. 单继承 举个例子:下面的代码中。先是定义了一个 People 类,里面有一个 speak 方法。然后再定义一个 Student 类,并继承自 People 类。 ```python # 父类定义 class People: def __init__(self, name, age, weight): self.name = name self.age = age def speak(self): print(f"{self.name} 说: 我{self.age}岁。") # 单继承示例 class Student(People): def __init__(self, name, age, weight, grade): # 调用父类的实例化方法 People.__init__(self, name, age, weight) self.grade = grade ``` 由于继承的机制,Student 实例会拥有 People 类所有属性和方法,比如下边我可以直接调用 People 类的 speak 方法。 ```python >>> xm = Student(name="小明", age=10, weight=50, grade="三年级") >>> xm.speak() 小明 说: 我 10 岁。 ``` 你如果不想使用父类的方法,你可以重写它以覆盖父类的 `speak` 方法。 ```python # 单继承示例 class Student(People): def __init__(self, name, age, weight, grade): # 调用父类的实例化方法 People.__init__(self, name, age, weight) self.grade = grade # 重写父类的speak方法 def speak(self): print(f"{self.name} 说: 我{self.age}岁了,我在读{self.grade}") ``` 此时,再调用的话,就会调用自己的方法了 ```python >>> xm = Student(name="小明", age=10, weight=50, grade="三年级") >>> xm.speak() 小明 说: 我10岁了,我在读三年级 ``` ## 2. 多继承 Python 还支持多继承,可以继承自多个类。 ```python class 子类(父类1, 父类2, 父类3...): ``` 多继承的话,情况会比单继承复杂得多。 假设多个父类都有一个 foo 方法,并且子类没有重写 foo 方法,那么 子类 的实例在调用 foo 方法时,应该使用哪个父类的 foo 方法呢? 关于这一点,只要简单的做个验证就行啦。 有如下代码,定义了 7 个类 ```python class D:pass class C(D):pass class B(C): def show(self): print("i am B") class G:pass class F(G):pass class E(F): def show(self): print("i am E") class A(B, E):pass ``` 它们的继承关系是 ![](http://image.iswbm.com/image-20201213150058921.png) 运行后的结果如下 ```python >>> a = A() >>> a.show() i am B ``` 在类A中,没有show()这个方法,于是它只能去它的父类里查找,它首先在B类中找,结果找到了,于是直接执行B类的show()方法。可见,在A的定义中,继承参数的书写有先后顺序,写在前面的被优先继承。 ## 3. 继承顺序 那如果B没有show方法,而是D有呢? ```python class D: def show(self): print("i am D") class C(D):pass class B(C):pass class G:pass class F(G):pass class E(F): def show(self): print("i am E") class A(B, E):pass ``` 执行结果是 ```python >>> a = A() >>> a.show() i am D ``` 由此可见,多继承的顺序使用的是从左向右再深度优先的原则。 ![](http://image.iswbm.com/image-20201213151434342.png) ## 4. MRO 算法 上面的继承案例是只是非常简单的一种场景,在实际应用中,会远比这个来得复杂。 此时如果你单纯的将其理解成 - 从左向右 - 深度优先 就会发现很场景下想要理清的方法解析顺序(MRO)是非常难的。 在这种情况下,你还可以有两种方法: 1. 使用 `__mro__` 来查询 2. 使用 merge算法进行推导 ### 使用 mro 查询 比如在下面这个菱形继承中 ```python class A(object):pass class B(A):pass class C(A):pass class D(B, C):pass ``` ![](http://image.iswbm.com/20201004123106.png) 可以使用 `__mro__` ```python >>> print(D.__mro__) ``` 或者借助 inspect 模块 ```python >>> import inspect >>> print inspect.getmro(D) ``` 得到的结果都将是 ```python (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) ``` ### 使用 merge 推导 ![](http://image.iswbm.com/20201004123115.png) 1. 检查第一个列表的头元素(如 L[B1] 的头),记作 H。 2. 若 H 未出现在其它列表的尾部,则将其输出,并将其从所有列表中删除,然后回到步骤1;否则,取出下一个列表的头部记作 H,继续该步骤。 3. 重复上述步骤,直至列表为空或者不能再找出可以输出的元素。如果是前一种情况,则算法结束;如果是后一种情况,说明无法构建继承关系,Python 会抛出异常。 你可以在草稿纸上,参照上面的merge算法,写出如下过程 ``` L[object] = [object] L[D] = [D, object] L[E] = [E, object] L[F] = [F, object] L[B] = [B, D, E, object] L[C] = [C, D, F, object] L[A] = [A] + merge(L[B], L[C], [B], [C]) = [A] + merge([B, D, E, object], [C, D, F, object], [B], [C]) = [A, B] + merge([D, E, object], [C, D, F, object], [C]) = [A, B, C] + merge([D, E, object], [D, F, object]) = [A, B, C, D] + merge([E, object], [F, object]) = [A, B, C, D, E] + merge([object], [F, object]) = [A, B, C, D, E, F] + merge([object], [object]) = [A, B, C, D, E, F, object] ``` ## 附录:参考文章 --- - https://www.python.org/download/releases/2.3/mro/ - https://www.cnblogs.com/whatisfantasy/p/6046991.html