继承:
什么是继承?
继承是一种新建类的方式,新建的类称之为字类或派生类,继承的父类称之为基类或超类。
在python中,一个子类可以继承多个父类。
在其他语言中,一个子类只能继承一个父类。
继承的作用:
解决代码的冗余。
如何实现继承?
1.先确认谁是子类,谁是父类。
2.在定义类子类时,子类名(父类名)。
# 父类 class Father1: x = 1 pass class Father2: pass #子类 class Sub(Father1, Father2): pass #子类.__bases__查看父类 print(Sub.__bases__) print(Sub.x)
如何寻找继承关系:
1.确认谁是子类
2.确认谁是父类
-- 抽取对象之间相似的部分总结出类。
--抽取类之间相似的部分,总结出父类。
#代码冗余: #老师类 class OldboyTeacher: 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}正在修改分数...') #学生类 class OldboyStudent: school = 'oldboy' country = 'China' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex #学生选课程 def choose_course(self): print(f'学生{self.name}正在选择课程...') #学生类 stu1 = OldboyStudent('AA', 19, 'female') print(stu1.school, stu1.name, stu1.age, stu1.sex) #oldboy AA 19 female #老师 tea1 = OldboyTeacher('tank', 18, 'male') print(tea1.school, tea1.name, tea1.age, tea1.sex) # oldboy tank 18 male # 解决代码冗余问题 #老男孩人类 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('AA', 39, 'female') print(stu1.school, stu1.name, stu1.age, stu1.sex)#oldboy AA 39 female tea1 = OldboyTeacher('大脸', 75, 'female') print(tea1.school, tea1.name, tea1.age, tea1.sex)#oldboy 大脸 75 female
继承背景下对象属性的查找顺序
注意: 程序的执行顺序是由上到下,父类必须定义在子类的上方。
-- 在继承背景下,对象属性的查找顺序:
1.先从对象自己的名称空间中查找
2.对象中没有,从子类的名称空间中查找。
3.子类中没有, 从父类的名称空间中查找,若父类没有,则会报错!
派生
指的是子类继承父类的属性与方法,并且派生出自己独有的属性与方法。
若子类中的方法与父类的相同,优先用子类的。
#父类: 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... bar_obj = Bar() bar_obj.f2() #from Foo.f2... #from Bar.f1... #因为子类和父类中的方法名一样,优先使用子类名,
子类继承父类并重用父类的属性与方法
子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法。
问题: 子类重写父类的_ _ init _ _ 导致代码更加冗余
解决问题:子类重用父类的属性,并派生出新的属性
--两种方式:
--1.直接引用父类的_ _ init _ _为其传参,并添加子类的属性。
--2.通过super来指向父类的属性。
--super()是一个特殊的类,调用super得到一个对象,该对象指向父类的名称空间。
注意: 使用哪一种都可以,但不能两种方式混合使用。
#解决方法 #方式一 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 # #类调用类内部的__init__,值时一个普通函数 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('姚玉鑫', 28, 'male', '凤姐') print(stu1.name, stu1.age, stu1.sex, stu1.girl) #方法二 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): 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('姚玉鑫', 28, 'male', '凤姐') print(stu1.name, stu1.age, stu1.sex, stu1.girl)
经典类与新式类(了解)
新式类:
--1.凡是继承object的类或子孙类都是新式类。
--2.在python3中所有的类都默认继承object。
经典类:
--1.在python2中才会有经典类与新式类之分。
--2.在python2中,凡是没有继承object的类,都是经典类。
supre严格遵循mro继承顺序
调用mro返回的是一个继承序列: (了解知识点)
super的继承顺序严格遵循mro继承序列。
在python3中提供了一个查找新式类查找顺序的内置方法. mro(): 会把当前类的继承关系列出来。
class Father1: x = 10 pass class Father2: x = 20 pass #多继承的情路况下:从左到右 class Sub(Father1, Father2): def __init__(self): print(super().__delattr__) print(Sub.mro()) obj = Sub() 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()