面向对象之继承与派生
一、继承
1、什么是继承
继承是一种新建类的方式,新建的类称之为子类或派生类,继承的父亲称之为基类或超类。
- 在Python中,一个子类可以继承多个父类。
- 在其它语言中,一个子类只能继承一个父类。
如何实现继承
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,父类是ParentClass1,派生类是SubClass1 pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类 pass SubClass1.__base__ #__base__只查看从左到右继承的第一个子类 >>> (<class '__main__.ParentClass1'>,) SubClass2.__bases__ #__bases__则是查看所有继承的父类 >>> (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
要找出类与类之间的继承关系,需要先抽象,再继承。
- 抽取对象之间相似的部分,总结出类
- 抽取类之间相似的部分,总结出父类。
抽象即总结相似之处,总结对象之间的相似之处得到类,总结类与类之间的相似之处就可以得到父类,如下图所示
二、在继承背景下,对象属性的查找顺序:
- 先从对象自己的名称空间中查找
- 对象中没有,从子类的名称空间中查找
- 子类中没有, 从父类的名称空间中查找,若父类没有,则会报错!
三、派生:
派生 指的是子类继承父类的属性与方法,并且派生出自己独有的属性与方法。
若子类中的方法名与父类的相同,优先使用子类的。
#父类 class Foo: def f1(self): print('from foo.f1...') def f2(self): #self --->bar_obj print('from foo.f2...') #bar_obj.f1() ---> 对象自己找 ---> Bar ---> Foo self.f1() #子类 class Bar(Foo): #重写 def f1(self): print('from Bar.f1...') def func(self): print('from Bar.func...') bar_obj = Bar() bar_obj.f1() #from Bar.f1... bar_obj.f2() #from foo.f2... #from Bar.f1...
问题:字类重写父类的__init__导致代码更加冗余: class BjdxPeople: school = 'Bjdx' def __init__(self,name,age,sex,sal): self.name = name self.age = age self.sex = sex self.sal = sal class BjdxTeacher(BjdxPeople): def __init__(self,name,age,sex,sal): self.name = name self.age = age self.sex = sex self.sal = sal def change_score(self): print(f'老师{self.name}修改分数...') class BjdxStudent(BjdxPeople): def __init__(self,name,age,sex,girl): self.name = name self.age = age self.sex = sex self.girl = girl def choose_course(self): print(f'学生 {self.name} 选择课程...') tea1 = BjdxTeacher('tank',66,'male',15000) stu1 = BjdxStudent('baohan',18,'male','小花') print(tea1.name, tea1.age, tea1.sex, tea1.sal) print(stu1.name, stu1.age, stu1.sex, stu1.girl)
''' 解决问题: 子类重用父类的属性,并派生出新的属性。 两种方式: 1.直接引用父类的__init__为其传参,并添加子类的属性。 2.通过super来指向父类的属性。 - super()是一个特殊的类,调用super得到一个对象,该对象指向父类的名称空间。 注意: 使用哪一种都可以,但不能两种方式混合使用。 ''' 方式一:指名道姓地调用,(其实与继承是没有什么关系的) class BjdxPeople: school = 'oldboy' def __init__(self, name, age, sex): # self == tea1, name == 'tank', age == 17, sex == 'male' self.name = name self.age = age self.sex = sex class BjdxTeacher(BjdxPeople): # tea1, 'tank', 17, 'male', 15000000 def __init__(self, name, age, sex, sal): # self.name = name # self.age = age # self.sex = sex # 类调用类内部的__init__,只是一个普通函数 # BjdxPeople.__init__(tea1, 'tank', 17, 'male') BjdxPeople.__init__(self, name, age, sex) self.sal = sal def change_score(self): print(f'老师 {self.name} 修改分数...') class BjdxStudent(BjdxPeople): def __init__(self, name, age, sex, girl): BjdxPeople.__init__(self, name, age, sex) self.girl = girl def choose_course(self): print(f'学生 {self.name} 选择课程...') tea1 = BjdxTeacher('tank', 17, 'male', 15000) print(tea1.name, tea1.age, tea1.sex, tea1.sal) stu1 = BjdxStudent('baohan', 28, 'male', '小花') print(stu1.name, stu1.age, stu1.sex, stu1.girl)
方式二:super()调用,此方式(严格)依赖于继承 super()的返回值是一个特殊的对象,该对象专门用来调用父类中的属性 #了解:在python2中, 需要super(自己的类名,self) class BjdxPeople: school = 'Bjdx' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex class BjdxTeacher: def __init__(self,name,age,sex,sal): super().__init__(name,age,sex) self.sal = sal def change_score(self): print(f'老师 {self.name} 修改分数...') class BjdxStudent(BjdxPeople): def __init__(self, name, age, sex, girl): super().__init__(name, age, sex) self.girl = girl def choose_course(self): print(f'学生 {self.name} 选择课程...') tea1 = BjdxTeacher('tank', 17, 'male', 15000) print(tea1.name, tea1.age, tea1.sex, tea1.sal) stu1 = BjdxStudent('baohan', 28, 'male', '小花') print(stu1.name, stu1.age, stu1.sex, stu1.girl)