面向对象之继承
一.继承
1.1什么是继承
继承一种新建类的方式,新建的类称之为子类/派生类,被继承的类称之为父类\基类\超类
ps:派生类是在继承父类的基础上有一些自己的属性或者技能(有和父类不一样的东西)
1.2为什么要用继承
为了减少代码的冗余,重用已有的代码,提高重用性
1.3python中继承有何特点:
1.子类可以遗传/重用父类的属性
2.python中一个子类可以同时继承多个父类
3.在继承背景下去说,python中的类分为两种:新式类,经典类
经典类和新式类:
经典类:经典类只存在与python2中,在书写时没有继承object类,或者继承osject类的子类
新式类:在python3中全都是新式类,在python2中继承了object的类都叫做新式类
1.4继承的基本语法
class Foo: pass class Student(Foo): pass 基本语法:class 类名(要继承的类名):
1.5继承的注意事项
1.先抽象在继承
2.继承一个现有的类,扩展或者修改原始的功能
ps:抽象就是将多个子类中的相同部分进行抽取,形成一个新的类
二.如何用继承关系解决类和类之间代码冗余的问题
class OldboyStudent: def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex class OldboyTeacher: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex stu1=OldboyStudent('刘',38,'male') print(stu1.__dict__) tea1=OldboyTeacher('zhang',18,'male') print(tea1.__dict__)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class OldboyPeople: school = 'Oldboy' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex class OldboyStudent(OldboyPeople): pass class OldboyTeacher(OldboyPeople): pass stu1=OldboyStudent('刘',38,'male') print(stu1.__dict__) tea1=OldboyTeacher('zhang',18,'male') print(tea1.__dict__)
三.在子类派生出的新方法中重用父类的功能集中方式
3.1指名道姓的方式(__init__)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class OldboyPeople: school = 'Oldboy' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex class OldboyStudent(OldboyPeople): def __init__(self, name, age, sex, score=0): OldboyPeople.__init__(self,name,age,sex) self.score = score def choose_course(self): print('%s choosing course' % self.name) class OldboyTeacher(OldboyPeople): def __init__(self,name,age,sex,level): OldboyPeople.__init__(self,name,age,sex) self.level=level def score(self,stu,num): stu.score=num stu1=OldboyStudent('刘',38,'male') print(stu1.__dict__) tea1=OldboyTeacher('zhang',18,'male',10) print(tea1.__dict__)
ps:1.该方式和继承没有任何关系 2.访问是类的函数,没有自动传值的效果,需要几个参数就要传几个 3.当你继承一个现有的类,并且你覆盖 了父类的init方法时,必须在初始化方法的第一行调用父类的初始化方法,并传入父类所需的参数
3.2方式二super
在python2中:super(自己的类名,自己的对象).你要调的父类的属性或方法
在python3中:super().你要调的父类的属性或方法
ps:1. 严格依赖继承的mro列表
2. 访问是绑定方法,有自动传值的效果
ps:mro列表是由类名.mro()产生的一个列表,属性的查找会严格按照这个来执行,即后面的类名一定是前一个的爹
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class OldboyPeople: school = 'Oldboy' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex class OldboyStudent(OldboyPeople): def __init__(self, name, age, sex, score=0): super(OldboyStudent,self).__init__(name,age,sex) self.score = score class OldboyTeacher(OldboyPeople): def __init__(self,name,age,sex,level): super().__init__(name,age,sex) self.level=level stu1=OldboyStudent('刘',38,'male') print(stu1.__dict__) tea1=OldboyTeacher('zhang',18,'male',10) print(tea1.__dict__)
四.属性查找的顺序
1.在单继承背景下的查找顺序对象->对象的类->父类->......
class Foo: def f1(self): print('Foo.f1') def f2(self): print('Foo.f2') self.f1() # obj.f1()此处会先找obj自己,然后去所属的类Bar中寻找 class Bar(Foo): def f1(self): print('Bar.f1') obj=Bar() obj.f2()
2.在多继承背景下的查找顺序
4.2.1如果一个子类继承多个分支(多个分支没有共同继承一个非object的类)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class H: x='H' class E: x='E' class F(H): x='F' class G: x='G' class B(E): x='B' class C(F): x='C' class D(G): x='D' class A(B,C,D): x='A' print(A.mro()) #[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.H'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>]
查找顺序是对象-->对象的类-->按照从左到右的顺序一个分支一个分支的找完
4.2.2 菱形继承
4.2.2.1新式类:广度优先,最后才去找最后的一个类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class H: x='H' class E(H): x='E' class F(H): x='F' class G(H): x='G' class B(E): x='B' class C(F): x='C' class D(G): x='D' class A(B,C,D): x='A' print(A.mro())
4.2.2.2经典类(深度优先)深度优先查找,从左往右一个分支一个分支的查找,在第一个定级类就去寻找
ps:当出现菱形继承时,新式类先深度,当遇到共同父类时就广度
经典类就是深度优先