继承与派生
继承
1.什么是继承
继承是一种新建类的方式,新建的类称之为子类或派生类,继承的父类称之为基类或超类。
-在Python中,一个子类可以继承多个父类。
-在其他语言中,一个子类只能继承一个父类。
2.继承的作用
减少代码的冗余。
3.如何实现继承
1)先确认谁是子类,谁是父类
2)在定义类子类时,子类名(父类名)
#父类 class Father1: x = 1 pass class Father2: pass class Father3: pass #子类 class Sub(Father1,Father2,Father3) pass #子类.__bases__查看父类 print(Sub.__bases__) print(Sub.x)
如何寻找继承关系
-确认谁是子类
-sean对象 --->人子类 --->动物父类
-小猪佩奇对象 --->猪子类 --->动物父类
-哈士奇对象 --->狗子类 --->动物父类
-再确认谁是父类
-动物类就是父类
-得先抽象,再继承
-抽取对象之间相似的部分,总结出类
-抽取类之间相似的部分,总结出父类
问题:代码冗余 #老师类 class OldTeacher: school = 'oldboy' country = 'China' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex #老师修改分数 def change_score(self): print(f'老师{self.name}正在修改分数...') #学生类 calss OldboyStudent: school = 'oldboy' country = 'China' def__init__(self,name,age,sex): self.name = name self.age = age self.age = sex #学生选择课程 def choose_course(self) print(f'学生{self.name}正在选择课程...') stu1 = OldboyStudent('XXX',18,'male') print(stu1.school,stu1.name,stu1.age,stu1.sex) tea1 = OldboyTeacher('sean',18,'male') print(tea1.school,tea1.name,tea1.age,tea1.sex) #解决代码冗余问题 class OldboyPeople: school = 'oldboy' country = 'China' def__init__(self,name,age,sex): self.name = name self.age = age self.sex = sex #老师类 class OldboyTeacher(OldboyPeople): #老师修改分数 def change_score(self): print(f'老师{self.name}正在修改分数...') #学生类 class OldboyStudent(OldboyPeople): #学生选择课程 def choose__course(self): print(f'学生{self.name}正在选择课程...') stu1 OldboyStudent('XXX',18,'male') print(stu1.school,stu1.name,stu1.age,stu1.sex) tea1 = OldboyTeacher('sean',18,'male') print(tea1.school,tea1.name,tea1.age,tea1.sex)
注意:程序的执行顺序是由上到下,父类必须定义在子类的上方。
-在继承背景下,对象数学的查找顺序:
1.先从对象自己的名称空间中查找
2.对象中没有,从子类的名称空间中查找。
3.子类中没有,从父类的名称空间中查找,若父类没有,在会报错!
#父类 class Goo: x = 10 pass #子类 class Foo(Goo): x = 100 pass foo_obj = Foo() #foo_obj.x = 1000 #对象添加属性的操作,并不是修改子类的属性 print(foo_obj.x) print('对象的名称空间:',foo_obj.__dict__) print('子类的名称空间: ',Foo.__dict__) print('父类的名称空间: ',Goo.__dict__)
派生
派生:指的是子类继承父类的属性与方法,并且派生出自己独有的属性与方法。
若子类中的方法名与父类的相同,优先用子类的。
#父类 class Foo: def f1(self): print('from Foo.f1...') def f2(self): print('from Foo.f2...') 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.func() # from Bar.func... # bar_obj.f2() # from Foo.f2...
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, sal): self.name = name self.age = age self.sex = sex self.sal = sal def change_score(self): print(f'老师 {self.name} 修改分数...') class OldboyStudent(OldboyPeople): 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 = OldboyTeacher('tank', 17, 'male', 15000000) stu1 = OldboyStudent('XXX', 28, '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 OldboyPeople: 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 OldboyTeacher(OldboyPeople): # tea1, 'tank', 17, 'male', 15000000 def __init__(self, name, age, sex, sal): # self.name = name # self.age = age # self.sex = sex # 类调用类内部的__init__,只是一个普通函数 # OldboyPeople.__init__(tea1, 'tank', 17, 'male') OldboyPeople.__init__(self, name, age, sex) self.sal = sal def change_score(self): print(f'老师 {self.name} 修改分数...') class OldboyStudent(OldboyPeople): def __init__(self, name, age, sex, girl): OldboyPeople.__init__(self, name, age, sex) self.girl = girl def choose_course(self): print(f'学生 {self.name} 选择课程...') tea1 = OldboyTeacher('tank', 17, 'male', 15000000) print(tea1.name, tea1.age, tea1.sex, tea1.sal) stu1 = OldboyStudent('XXX', 28, 'male', '凤姐') print(stu1.name, stu1.age, stu1.sex, stu1.girl) # 方式二: class OldboyPeople: school = 'oldboy' # self == tea1 def __init__(self, name, age, sex): # self == tea1, name == 'tank', age == 17, sex == 'male' self.name = name self.age = age self.sex = sex class OldboyTeacher(OldboyPeople): # tea1, 'tank', 17, 'male', 15000000 def __init__(self, name, age, sex, sal): # super() ---> 特殊的对象 ---> 对象.属性 ---> 父类的名称空间 # 会将调用类传入的对象当做第一个参数传给__init__() super().__init__(name, age, sex) self.sal = sal def change_score(self): print(f'老师 {self.name} 修改分数...') class OldboyStudent(OldboyPeople): def __init__(self, name, age, sex, girl): super().__init__(name, age, sex) self.girl = girl def choose_course(self): print(f'学生 {self.name} 选择课程...') tea1 = OldboyTeacher('tank', 17, 'male', 15000000) print(tea1.name, tea1.age, tea1.sex, tea1.sal) stu1 = OldboyStudent('XXX', 28, 'male', '凤姐') print(stu1.name, stu1.age, stu1.sex, stu1.girl)
1.凡是继承object的类或子孙类都是新式类。
2.在python3中所有的类都默认继承object。
-经典类:
1.在python2中才会有经典类与新式类之分。
class User(object): pass class User: # (<class 'object'>,) x = 10 pass class Sub(User): pass print(User.__dict__) print(object)
钻石继承(菱形继承)
多继承情况下造成“钻石继承”
mro的查找顺序:
-新式类
-广度优先
-经典式
-深度优先
class A(object): # def test(self): # print('from A') pass class B(A): # def test(self): # print('from B') pass class C(A): # def test(self): # print('from C') pass class D(B): # def test(self): # print('from D') pass class E(C): # def test(self): # print('from E') pass class F(D, E): # def test(self): # print('from F') pass # F-->D-->B-->E-->C-->A-->object # print(F.mro()) obj = F() obj.test()