一、继承
类的继承
- 面向对象三要素之一,继承Inheritance
- class Cat(Animal)这种形式就是从父类继承,继承可以让子类从父类获取特征(属性和方法)
在面向对象的世界中,从父类继承,就可以直接拥有父类的属性和方法,这样可以减少代码,多复用,子类可以定义自己的属性和方法
1、查看继承的特殊属性和方法
- base : 类的基类
- based : 类的基类元组
- mro : 显示方法查找顺序,基类的元组
- __mro()__方法 : 显示方法查找顺序,基类的元组
subclasses() : 类的子类列表
2、继承中的查找顺序
- 从父类继承,自己没有的就可以到父类中找
- 私有的都是不可以访问的,但是本质上依然是改了名称放在这个属性所在类的_dict-中
- 继承时,公有的,子类和实例都可以随意访问,私有成员被隐藏了,子类和实例不可直接访问
- 当私有变量所在的类内的方法中可以访问这个私有变量
- 属性查找属性:实例的dict--》类的dict--》父类dict
多继承
- OCP原则:多继承,少修改;继承的用途:增强基类,实现多
1、多态
- 在面向对象中,父类,子类通过继承联系在一起,如果可以通过一套方法,就可以实现不同的表现,就是多态
- 一个类继承自多个类就是多继承,它将具有多个类的特征
2、多继承弊端
- 多继承很好的模拟了世界,因为事物很少是单一继承,但是舍弃简单,必然引入复杂性带来冲突
- 如同一个孩纸继承了来自父母双方的特征
- 多继承的实现会导致编译器设计的复杂度增加,所以现在很多语言也舍弃了类的多继承
3、python多继承实现
- 多继承带来路径选择问题,究竟继承哪个父类的特征
- python使用MRO(method resolution order)解决基类搜索顺序问题
4、多继承的缺点
- 当类很多,继承复杂的情况下,继承路径太多,很难说清楚什么样的继承路径
- python语法是允许多继承,但是python代码是解释执行,只有执行到的时候才发现错误
5、用装饰器增强
- 用装饰器增强一个类,把功能给类附加上去,哪个类需要,就装饰它
- 优点:简单方便,在需要的地方动态增加,直接使用装饰器
二、派生
派生:子类定义自己新的属性,如果与父类同名,以子类自己的为准
在子类派生出的新方法中重用父类的功能:
方式一:指名道姓地调用(与继承没有什么关系)
方式二:super()调用(严格依赖于继承)
super ( ) 的返回值是一个特殊的对象,该对象专门用来调用父类中的属性,super()会严格按照mro列表从当前查找到的位置继续往后查找
经典类和新式类:
1、新式类: 继承object的类,以及该类的子类,都是新式类
在python3中,如果一个类没有指定继承的父类,默认就继承object,所以说python3中所有的类都是新式类
2、经典类(只有在python2才区分经典类与新式类):没有继承object的类,以及该类的子类,都是经典类
在多继承背景下的属性查找:
属性查找
obj.x
1、先从obj.__dict__
2、对象的类.__dict__
3、父类.__dict__
如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性
如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先
print(F.__mro__) # F.mro() #只有新式类才有这个属性可以查看线性列表,查看属性查找顺序,经典类没有这个属性
类的组合
- 组合就是一个类的对象具备某一个属性,该属性的值是指向另外一个类的对象
- 组合的好处:解决类与类之间代码冗余的问题
组合的应用
- 需求:假如我们需要给学生增添课程属性,但是又不是所有的学生一进学校就有课程属性,课程属性是学生选出来的,也就是说课程需要后期学生们添加进去
- 实现思路:如果我们直接在学生中添加课程属性,那么学生刚被定义就需要添加课程属性,这就不符合我们的要求,因此我们可以使用组合能让学生未来添加课程属性
菱形继承问题
在Python中子类可以同时继承多个父类,如A(B,C,D)
- 如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这条分支,最后找D这条分支的顺序直到找到我们想要的属性
- 如果继承关系为菱形结构,即子类的父类最后继承了同一个类,那么属性的查找方式有两种
经典类(了解)
一条路走到黑,深度优先
查找顺序:A -> B -> E -> G -> C -> F -> D
新式类
不找到各类最后继承的同一个类,直接去找下一个父类,广度优先
查找顺序:A -> B -> E -> C -> F -> D -> G
mro方法
python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,如:
print(A.__mro__) # 在此用python3运行,广度优先 (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>) for i in A.__mro__: print(i) <class '__main__.A'> <class '__main__.B'> <class '__main__.E'> <class '__main__.C'> <class '__main__.F'> <class '__main__.D'> <class '__main__.G'> <class 'object'>