在面向对象的中,类与类之间存在三种关系:依赖关系、组合关系、继承关系。
1、依赖关系: 将一个类的类名或对象当做参数传递给另一个函数被使用的关系就是依赖关系
2、组合关系:
将一个类的对象封装到另一个类的对象的属性中,就叫组合
3、继承关系
(1)什么是面向对象的继承
继承(英语:inheritance)是面向对象软件技术当中的一个概念。如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。
一般静态的面向对象编程语言,继承属于静态的,意即在子类别的行为在编译期就已经决定,无法在执行期扩充。
(2)程序中 A(B)
<1> A – 子类,派生类
<2> B – 父类,基类,超类
当我们写多个类的时候会发现许多问题如:
上述代码重复,这时我们可以简化相关代码如:
(3)继承的优点:
- 减少重复代码
- 结构清晰,规范
- 增加耦合性(耦合性不宜多,在精)
(4)继承的分类:
<1> 单继承
<2> 多继承
Python2: python2.2 之前都是经典类,python2.2之后出现了新式类,继承object就是新式类 Python3: 只有新式类,不管你继不继承object都是新式类
(5)单继承:
<1> 通过子类的类名使用父类的属性和方法
<2> 通过子类的对象使用父类的属性和方法
(6)查找顺序:
<1> 不可逆(就近原则)
<2> 通过子类,类名使用父类的属性或方法(查找顺序):当前类,当前类的父类,当前类的父类的父类---->
<3> 通过子类对象使用父类的属性或者方法(查找顺序):先找对象,实例化这个对象的类,当前类的父类—>
(7)同时使用子类和父类方法或属性:
<1> 方法一:不依赖(不需要)继承
<2> 方法二:依赖(需要)继承
习题练习:
(8)多继承
多继承是继承多个父类
多继承中, 存在着这样一个问题. 当两个⽗类中出现了重名⽅法的时候. 就会涉及到如何查找⽗类⽅法的这么⼀个问题.即MRO(method resolution order) 问题. 在python中这是一个很复杂的问题. 因为在不同的python版本中使用的是不同的算法来完成MRO的.
(1)经典类:多继承时从左向右执行
总结:
经典类:(深度优先)左侧优先,一条路走到头,找不到会回到起点向右查询
(2)新式类:采用c3算法 (也有说用广度优先的 – 不精确)
(3)c3 算法的核心 mro
<1> mro() – python提供的可以查看多继承时的执行顺序的一种方法
<2> MRO是一个有序列表L,在类被创建时就计算出来。通用计算公式为:
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] ) (其中Child继承自Base1, Base2)
如果继承至一个基类:class B(A) 这是B的mro序列为
如果继承至多个基类:class B(A1, A2, A3 …) 这时B的mro序列
计算结果为列表,列表中至少有一个元素即类自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。
<3> 表头和表尾
表头: 列表的第一个元素
表尾: 列表中表头以外的元素集合(可以为空)
示例 列表:[A, B, C] 表头是A,表尾是B和C
<4> 列表之间的+操作
+操作:
[A] + [B] = [A, B] (以下的计算中默认省略) ---------------------
merge操作示例:
<5> 经典类不能使用mro , 新式类才能使用mro