Python继承¶
注解
继承是一种偷懒的方式.
如果已经有了一个类, 并要创建一个与之很像的类(可能只是新增了几个方法), 该如何办呢? 可以在创建这个新类时, 复制旧类的代码, 但还有更好的方式: 继承.
继承, 是根据已有的类创建新的类. 新类继承了已有类的所有属性和方法, 并可在已有类的基础上添加一些成员(属性和方法), 或修改继承的方法, 通过使用继承机制, 可以轻松实现类的复用.
在Python中, 实现继承的类称为子类,被继承的类称为超类(也可称为基类, 父类).
子类继承超类时, 只需要在定义子类时, 将超类(可以是多个)放在子类之后的圆括号中即可:
class 类名(超类1, 超类2, ...):
...
- 子类继承超类的所有属性和方法;
- 可以在子类中重写从超类继承的方法.
注解
对于新式类, 如果该类没有显式指定继承自哪个类, 则默认继承object(object类是Python中所有类的超类, 即要么是直接超类, 要么是间接超类).
另外, Python支持多重继承, 即一个子类可以同时拥有多个直接超类.
多重继承¶
大部分面向对象的编程语言都只支持单继承, 即子类只能有一个父类, 而Python支持多重继承(C++也支持多重继承), 即一个子类可以从多个父类继承. 和单继承相比, 多重继承容易让代码逻辑复杂, 思路混乱, 一直备受争议, Java/C#/PHP等干脆取消了多重继承.
使用多重继承时, 有一点务必注意: 如果多个父类以不同的方式实现了同一个方法(即有多个同名方法), 必须在class语句中小心排列这些父类, 因为位于前面的类中的方法将覆盖位于后面的类的同名方法.
注解
多重继承是一个功能强大的工具, 然而, 除非确实有需要, 否则应该避免使用多重继承, 因为在有些情况下, 它可能带来意外的并发症.
方法解析顺序(MRO)¶
Python支持(多)继承, 一个类的方法和属性可能定义在当前类, 也可能定义在父类. 对于这种情况, 当调用类方法或者属性时, 就需要对当前类以及它的基类进行搜索, 以确定方法或属性的位置, 而搜索的顺序就称为方法解析顺序.
方法解析顺序(Method Resolution Order), 简称MRO. 对于只支持单继承的编程语言来说, MRO很简单, 就是从当前类开始, 逐个搜索它的父类; 而对于Python, 它支持多重继承, MRO相对会复杂一些.
实际上, Python发展至今, 经历了以下3种MRO算法, 分别是:
- 从左往右, 采用深度优先搜索(DFS)的算法, 称为旧式类的MRO;
- 自Python 2.2开始, 新式类在采用深度优先搜索算法的基础上, 对其做了优化;
- 自Python 2.3开始, 对新式类采用了C3算法. 由于Python 3.x只支持新式类, 所以只支持C3算法.
C3算法可以确保:
- 父类不比子类先查找;
- 如果有多个父类, 先查找定义在前面的父类.
一些函数¶
- 要确定一个类是否是另一个类的子类, 可以使用内置函数
issubclass(); - 如果想知道一个类的基类, 可以访问其特殊属性
__bases__; - 要确定一个对象是否是一个类的实例, 可以使用内置函数
isinstance().
注解
使用isinstance通常不是良好的做法, 依赖多态在任何情况下都是更好的选择.
一个重要的例外情况是使用抽象基类和模块abc时.