七.面向对象之继承与派生
一.初认识继承
1.1什么是继承
继承一种新建类的的方式,在python中支持一个儿子继承多个爹。新建的类称为子类或者派生类,父类又可以称为基类或者超类, 子类会”遗传“父类的属性。
1.2为什么要用继承
为了减少代码的冗余
1.3怎么用继承
class ParentClass1: pass class ParentClass2: pass class Subclass1(ParentClass1): pass class Subclass2(ParentClass1,ParentClass2):#可以继承多个父类 pass print(Subclass1.__bases__) print(Subclass2.__bases__) #查看自己的父类 继承相关代码
二.继承与抽象(先抽象再继承)
继承描述的是子类与父类之间的关系,是一种什么是什么的关系。要找出这种关系,必须先抽象再继承
抽象即抽取类似或者说比较像的部分。 抽象分成两个层次: 1.将奥巴马和梅西这俩对象比较像的部分抽取成类; 2.将人,猪,狗这三个类比较像的部分抽取成父类。 抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)
继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。
抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类
三.继承关系与继承的属性查找
3.1寻找继承关系
class OldboyPeople: school='oldboy' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def f1(self): print('爹的f1') class OldboyTeacher(OldboyPeople): def change_score(self): print('teacher %s is changing score'%self.name) tea1=OldboyTeacher('egon',18,'male')#OldboyTeacher.__init__(...) 实例化 print(tea1.__dict__) print(tea1.name) print(tea1.school) tea1.f1() class Foo: def f1(self): print('Foo.f1') def f2(self): print('Foo.f1') self.f1() class Bar(Foo): def f1(self): print('Bar.f1') obj=Bar() obj.f2()
3.2基于继承再看属性查找
class OldboyPeople: school = 'oldboy' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def f1(self): print('爹的f1') class OldboyTeacher(OldboyPeople): def change_score(self): print('teacher %s is changing score' %self.name) tea1 = OldboyTeacher('egon', 18, 'male') # print(tea1.__dict__) # print(tea1.name) # print(tea1.school) # print(tea1.change_score) # print(tea1.f1) class Foo: def f1(self): print('Foo.f1') def f2(self): #self=obj print('Foo.f2') self.f1() #obj.f1() class Bar(Foo): def f1(self): print('Bar.f1') obj=Bar() # print(obj.__dict__) obj.f2() # 答案为所以先从自己开始找,再找父类 # Foo.f2 # Bar.f1
总结:查找顺序,从自己的类这里找,再从父类找。
四.派生
4.1什么是派生?继承和派生的区别是什么?
派生:在子类定义自己新的属性,如果与父类同名,以子类自己的为准(这是一种覆盖的效果)。
继承可以遗传父类的属性,派生可以定制自己的属性。
# #派生:在子类定义自己新的属性,如果与父类同名,以子类自己的为准(这是一种覆盖的效果) # class OldboyPeople: # school = 'oldboy' # # def __init__(self, name, age, sex): # self.name = name # self.age = age # self.sex = sex # # def f1(self): # print('爹的f1') # class OldboyTeacher(OldboyPeople): # def change_score(self): # print('teacher %s is changing score' %self.name) # # def f1(self): # print('儿子的f1') #得到的是儿子的f1 # # tea1 = OldboyTeacher('egon', 18, 'male') # tea1.f1() # # class OldboyPeople: school = 'oldboy' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def f1(self): print('爹的f1') class OldboyTeacher(OldboyPeople): def __init__(self,name,age,sex,level,salary): self.name=name self.age=age self.sex=sex self.level=level self.salary=salary def change_score(self): print('teacher %s is changing score' %self.name) def f1(self): print('儿子的f1') tea1 = OldboyTeacher('egon', 18, 'male',9,3.1) print(tea1.name,tea1.age,tea1.sex,tea1.level,tea1.salary) #继承可以遗传父类的属性,派生可以定制自己的属性
4.2在子类派生出的新方法中重用父类的功能
在子类派生出的新方法中重用父类的功能
方式一:指名道姓地调用(其实与继承没有什么关系的)
OldboyPeople.__init__(self,name, age, sex) class OldboyPeople: school = 'oldboy' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def tell_info(self): print(""" ===========个人信息========== 姓名:%s 年龄:%s 性别:%s """ %(self.name,self.age,self.sex)) class OldboyTeacher(OldboyPeople): # tea1,'egon', 18, 'male', 9, 3.1 def __init__(self, name, age, sex, level, salary): # self.name = name # self.age = age # self.sex = sex OldboyPeople.__init__(self,name, age, sex) self.level = level self.salary = salary def tell_info(self): OldboyPeople.tell_info(self) print(""" 等级:%s 薪资:%s """ %(self.level,self.salary)) tea1 = OldboyTeacher('egon', 18, 'male', 9, 3.1) # print(tea1.name, tea1.age, tea1.sex, tea1.level, tea1.salary) tea1.tell_info()
方式二:super()调用(严格依赖于继承)
super()的返回值是一个特殊的对象,该对象专门用来调用父类中的属性
了解:在python2中,需要super(自己的类名,self) 固定用法
class OldboyPeople: school = 'oldboy' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def tell_info(self): print(""" ===========个人信息========== 姓名:%s 年龄:%s 性别:%s """ %(self.name,self.age,self.sex)) class OldboyTeacher(OldboyPeople): # tea1,'egon', 18, 'male', 9, 3.1 def __init__(self, name, age, sex, level, salary): # OldboyPeople.__init__(self,name, age, sex) super(OldboyTeacher,self).__init__(name,age,sex) #这是python2的方法 self.level = level self.salary = salary def tell_info(self): # OldboyPeople.tell_info(self) super().tell_info() print(""" 等级:%s 薪资:%s """ %(self.level,self.salary)) tea1 = OldboyTeacher('egon', 18, 'male', 9, 3.1) # print(tea1.name, tea1.age, tea1.sex, tea1.level, tea1.salary) tea1.tell_info()
五.组合
5.1解决类与类之间代码冗余问题有两种解决方案
1、继承:描述的是类与类之间,什么是什么的关系
2、组合:描述的是类与类之间的关系,是一种什么有什么关系。一个类产生的对象,该对象拥有一个属性,这个属性的值是来自于另外一个类的对象
class Date: def __init__(self,year,mon,day): self.year = year self.mon = mon self.day = day def tell_birth(self): print('出生年月日<%s-%s-%s>' % (self.year, self.mon, self.day)) class OldboyPeople: school = 'oldboy' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex class OldboyTeacher(OldboyPeople): def __init__(self,name,age,sex,level,salary): super().__init__(name,age,sex) self.level=level self.salary=salary def change_score(self): print('teacher %s is changing score' %self.name) class Oldboystudent(OldboyPeople): def __init__(self,name,age,sex,course,): super().__init__(name,age,sex,) self.course=course def choose(self): print('student %s choose course' %self.name) tea1=OldboyTeacher('egon',18,'male',9,3.1) date_obj=Date(2000,1,1) date_obj.tell_birth() tea1.birth=date_obj # print(tea1.birth) # tea1.birth.tell_birth() # tea1.change_score() stu1=Oldboystudent('张三',16,'male','linux') stu1.birth=Date(2002,3,3) stu1.birth.tell_birth()
5.2组合练习
class OldboyPeople: school = 'oldboy' def __init__(self, name, age, sex,): self.name = name self.age = age self.sex = sex class OldboyTeacher(OldboyPeople): def __init__(self,name,age,sex,level,salary): super().__init__(name,age,sex) self.level=level self.salary=salary self.courses=[] def change_score(self): print('teacher %s is changing score' %self.name) def tell_course_info(self): print(('老师%s 教授的课程信息如下' %self.name).center(50,'=')) for course_obj in self.courses: course_obj.info() class Oldboystudent(OldboyPeople): def __init__(self,name,age,sex): super().__init__(name,age,sex,) self.courses=[] def choose(self): print('student %s choose course' %self.name) def tell_course_info(self): print(('学生%s 学习的课程信息如下' % self.name).center(50, '=')) for course_obj in self.courses: course_obj.info() class Course: def __init__(self,cname,period,price): self.cname=cname self.period=period self.price=price def info(self): print('课程信息<名字:%s 周期:%s 价钱:%s>' %(self.cname,self.period,self.price)) tea1=OldboyTeacher('egon',18,'male',9,3.1) stu1=Oldboystudent('张三',16,'male') python=Course('Python全栈开发','5mons',3000) linux=Course('Linux高级架构师','5mons',2000) go=Course('Go开发工程师','3mons',1000)
六.经典类与新式类
在python2中有经典类与新式类之分 在python3中全都为新式类 ''' 1、新式类: 继承object的类,以及该类的子类,都是新式类 在python3中,如果一个类没有指定继承的父类,默认就继承object 所以说python3中所有的类都是新式类 2、经典类(只有在python2才区分经典类与新式类): 没有继承object的类,以及该类的子类,都是经典类 '''
class Foo(object): pass class Bar(Foo): pass print(Foo.__bases__) print(Bar.__bases__)
六.在多继承背景下的属性查找
pass
七.super()依赖继承
super()会严格按照mro列表从当前查找到的位置继续往后查找
class A: def test(self): print('A.test') super().f1()#调用父类的test方法 class B: def f1(self): print('from B') class C(A,B): pass c=C() print(C.mro()) #C->A->B->object super是照这个列表来的 B是A的爹,A是C的爹 c.test()