一、 继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,新建的类可称为子类或派生类,父类又可称为基类或超类
class ParentClass1: #定义父类
pass
class ParentClass2: #定义父类
pass
class SubClass1(ParentClass1): #单继承
pass
class SubClass(ParentClass1,ParentClass2): #多继承
pass
通过类的内置属性__bases__可以查看类继承的所有父类
>>> SubClass2.__bases__
二、在python2中有经典类与新式类之分
新式类:继承了object类的子类,以及该子类的子类子子类。
经典:没有继承object类的子类,以及该子类的子类子子类。
在python3中没有继承任何类,那么会默认继承object类,所以 python3中所有的类都是新式类
三、python的多继承
优点:子类可以同时遗传多个父类的属生,最大限度地重用代码
缺点:
1、违背人的思维习惯:继承表达的是一种什么‘是'什么的关系
2、代码可读性会变差
3、不建议使用多继承,有可能会引发可恶的菱形问题 ,扩展性变差,
如果真的涉及到一个子类不可避免地要重用多个父类的属性,应该使用Mixins
为何要用继承:用来解决类与类之间代码冗余问题
三、如何实现继承
类与类之间存在冗余问题
class OldboyPeople:
school = 'OLDBOY'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
class Student(OldboyPeople):
def choose_course(self):
print('学生%s 正在选课'% self.name)
class Teacher(OldboyPeople):
def __init__(self,name,age,sex,salary,level):
OldboyPeople.__init__(self,name,age,sex) #指名道姓地跟父类去要
self.salary = salary
self.level = level
def score(self):
print('老师 %s正在给学生打分‘%self.name)
tea_obj = Teacher('egon',18,'male',3000,10)
print(tea_obj.__dict__)
tea_obj.score()
四、属性查找
有了继承关系,对象在查找属性时,先从对象自己的__dict__中找,如果没有则去子类上找,然后再去父类中找
class Foo:
def f1(self):
print('Foo.f1')
def f2(self):
print('Foo.f2')
self.f1()
class Bar(Foo):
def f1(self):
print('Foo.f1')
b = Bar()
b.f2()
Foo.f2
Foo.f1
五、菱形问题
大多数面向对象语言都不支持多继承,而在python中,一个子类是可以同时继承多个父类的,这固然可以带来一个子类可以对多个不同父类加以重用的好处,但也有可能引发著名的Diarmond problem菱形问题(或称钻石问题 )
菱形期实就是对下面这种继承结构的形象比喻。
这种继承结构下导致的问题称之为菱形问题 :如果A中有个方法,B和或C都重写了该方法,而D没有重写它,那么D继承的是哪个版本的方法:B的还是C的?
继承原理
python到底是如何实现继承的呢?对于你定义的每一个类,python都会计算出一个方法解析顺序(MRO)
python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不支深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1、子类会先于父类被检查
2、多个父类会根据它们在列表中的顺序被检查
3、如果对下一个类存在两个合法的选择,选择第一个父类
由对象发起的属生查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去
由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去
五、深度优先和广度优先
参照下述代码,多继承结构为非菱形结构,此时,会按照先找B这一条分支,然后再找C这条分支,最后找D这一条分支的顺序直到找到我们想要的属性
如果继承关系为菱形结构,那么经典类与新式类会有不同mro,分别对应属性的两种查找方式:
深度优先和广度优先
查找顺序为:obj>A>B>E>C>F>D>G>object