类的继承
一、什么是面向对象的继承?
- 继承是一种创建新类的方式,新建的类可称为子类或者派生类,父类可称基类或者超类
- python支持多继承,其他语言不支持多继承
- 继承可以使得子类别具有父类别的各种属性和方法。
- 在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。
继承的优点有哪些?
- 增加了类的耦合性
- 减少了重复代码
- 减少了重复代码
多继承的缺点:
- 违背了人的思维习惯:继承表达的是一种什么是什么的关系
- 代码可读性会变差
- 不推荐使用多继承,应该使用Mixins(变相的多继承)
例子:
class Father:
print('我是你的爸爸,是你的基类')
class Mother:
print('我是你的妈妈,也是你的基类')
'''
语法:
class 类名(要继承的类名1,要继承的类名2):
pass
'''
#单继承
class Son1(Father):
pass
#多继承
class Son2(Father,Mother):
pass
二、继承的分类
继承:可以分单继承,多继承。
在python2x版本中存在两种类.:
⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
python3x版本中只有一种类:
python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object
object:是一个内置的类,里面包含很多功能-
三、单继承详细介绍
3.1、属性查找顺序
代码示例:
#
class A:
def f1(self):
print('f1')
def f2(self):
print('f2')
self.f1()
#继承A类
class B(A):
def f1(self):
print('Bf1')
#实例化对象
obj = B()
obj.f2()
#输出
f2
Bf1
3.2、那么怎么让3.1中self.f1调用父类的f1函数而不是调用子类的f1函数呢?
看代码:
class A:
def f1(self):
print('f1')
def f2(self):
print('f2')
######方法一
A.f1(self)
#self.f1()
class B(A):
def f1(self):
print('Bf1')
obj = B()
obj.f2()
四、多继承详细介绍
4.1、多继承的菱形继承
大多数面向对象语言都不支持多继承,而在Python中,一个子类是可以同时继承多个父类的,这固然可以带来一个子类可以对多个不同父类加以重用的好处,但也有可能引发著名的菱形问题(或称钻石问题,有时候也被称为“死亡钻石”),菱形其实就是对下面这种继承结构的形象比喻
出现这种问题的原因是,当B、C都继承了A(AB都重现改方法),D继承了B、C,可是D没有重写改方法!那么D继承的是B的还是C的呢?
class A(object):
def test(self):
print('from A')
class B(A):
def test(self):
print('from B')
class C(A):
def test(self):
print('from C')
方式一:
class D(B,C):
pass
obj = D()
obj.test() # 结果为:from B
方式二:
class D(C,B):
pass
obj = D()
obj.test() # 结果为:from C
#这是为什么呢?看方法解析就知道啦!顺序看mro的顺序即可!
print(D.mro())
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
4.2、多继承的属性查找顺序原理
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
4.由对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去,
5.由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去(python2、3的mro算出来的顺序是不一样的)
4.3、深度优先和广度优先
class E:
def test(self):
print('from E')
class F:
def test(self):
print('from F')
class B(E):
def test(self):
print('from B')
class C(F):
def test(self):
print('from C')
class D:
def test(self):
print('from D')
class A(B, C, D):
# def test(self):
# print('from A')
pass
print(A.mro())
'''
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>]
'''
obj = A()
obj.test() # 结果为:from B
# 可依次注释上述类中的方法test来进行验证
4.4 Pyton Mixins机制
Mixins机制核心:
- 就是在多继承的背景下尽可能的 提升多继承的可读性
- 让多继承满足人的思维习惯:什么是什么
使用Mixin类实现多重继承要非常小心
- 首先它必须表示某一种功能,而不是某个物品,python 对于mixin类的命名方式一般以 Mixin, able, ible 为后缀
- 其次它必须责任单一,如果有多个功能,那就写多个Mixin类,一个类可以继承多个Mixin,为了保证遵循继承的“is-a”原则,只能继承一个标识其归属含义的父类
- 然后,它不依赖于子类的实现
- 最后,子类即便没有继承这个Mixin类,也照样可以工作,就是缺少了某个功能。(比如飞机照样可以载客,就是不能飞了)
加上Mixin,规范!
class Vehicle: # 交通工具
pass
class FlyableMixin:
def fly(self):
'''
飞行功能相应的代码
'''
print("I am flying")
class CivilAircraft(FlyableMixin, Vehicle): # 民航飞机
pass
class Helicopter(FlyableMixin, Vehicle): # 直升飞机
pass
class Car(Vehicle): # 汽车
pass
# ps: 采用某种规范(如命名规范)来解决具体的问题是python惯用的套路
五 、派生与方法重用
方法一:“指名道姓”地调用某一个类的函数
此方法不继承也可以调用其他类的属性
People.init(self,name,age,sex)加上这个即可,想要调用函数,还是得继承
class People:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def f1(self):
print(F'{self.name}是沙雕')
class hh():
def __init__(self,name,age,sex,level,love):
People.__init__(self,name,age,sex)
self.level = level
self.love = love
obj = hh('张三',18,'男',3500,'钱')
print(obj.name)
方法二:super()
- 调用super()会得到一个特殊的对象,该对象会参照当前类的mro,去当前类的父类中找属性
- 在python3中直接调用即可,python2-->super(当前类名称,self)
class People:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def f1(self):
print(F'{self.name}是沙雕')
#调用super()会得到一个特殊的对象,该对象会参照当前类的mro,去当前类的父类中找属性
class hh(People):
def __init__(self,name,age,sex,level,love):
super().__init__(name,age,sex)
self.level = level
self.love = love
obj = hh('张三',18,'男',3500,'钱')
print(obj.name)