1、什么是继承?
继承一种新建类的方式,新建的类称之为子类/派生类,被继承的类称之为父类\基类\超类
# 将所有共有的属性与方法抽离出,形成父类
# 父类是多个有共同点的普通类抽离共有属性与方法形成的类
2.python中继承的特点:
1 python中继承的特点: 2 1. 子类可以遗传/重用父类的属性 3 2. python中一个子类可以同时继承多个父类 4 3. 在继承背景下去说,python中的类分为两种:新式类,经典类 5 新式类: 但凡继承了object的类Foo,以及该类的子类...都是新式类 6 在python3中一个类即便是没有显式地继承任何类,默认就会继承object 7 即python3中所有的类都是新式类 8 9 经典类:没有继承object的类,以及该类的子类...都是经典类 10 在python2中才区分新式类与经典类, 11 在python2中一个类如果没有显式地继承任何类,也不会继承object
3 为何要用继承
减少类与类之间代码冗余
3 如何用继承
# 继承的规则
# 1.父类的所有未封装的属性和方法,子类都能访问
# 2.父类的所有封装的属性和方法,子类都不能访问
# -- 在外界通过子类或子类对象,不能访问
# -- 在子类内部通过子类或子类对象也不能访问
语法
1 # class Parent1(object): 2 # pass 3 # 4 # class Parent2(object): 5 # pass 6 # 7 # class Sub1(Parent1): 8 # pass 9 # 10 # class Sub2(Parent1,Parent2): 11 # pass 12 13 # print(Parent1.__bases__) 14 # print(Parent2.__bases__) 15 # print(Sub1.__bases__) 16 # print(Sub2.__bases__)
3.1利用继承来解决代码之间的冗余问题
例子
1 class OldboyPeople: 2 school = 'Oldboy' 3 4 def __init__(self,name,age,sex): 5 self.name = name 6 self.age = age 7 self.sex = sex 8 9 class OldboyStudent(OldboyPeople): 10 # def __init__(self, name, age, sex, score=0): 11 # self.name = name 12 # self.age = age 13 # self.sex = sex 14 # self.score = score 15 16 def choose_course(self): 17 print('%s choosing course' % self.name) 18 19 class OldboyTeacher(OldboyPeople): 20 # def __init__(self,name,age,sex,level): 21 # self.name=name 22 # self.age=age 23 # self.sex=sex 24 # self.level=level 25 26 def score(self,stu,num): 27 stu.score=num 28 29 30 stu1=OldboyStudent('刘二蛋',38,'male') 31 print(stu1.__dict__) 32 33 tea1=OldboyTeacher('egon',18,'male') 34 print(tea1.__dict__) 35
3.2 父类功能的重用
在子类派生出的新方法中重用父类功能的方式一:
# 指名道姓地引用某一个类中的函数
# 总结:
# 1. 与继承无关
# 2. 访问是类的函数,没有自动传值的效果
1 class OldboyPeople: 2 school = 'Oldboy' 3 4 def __init__(self,name,age,sex): 5 self.name = name 6 self.age = age 7 self.sex = sex 8 9 class OldboyStudent(OldboyPeople): 10 def __init__(self, name, age, sex, score=0): 11 OldboyPeople.__init__(self,name,age,sex) 12 self.score = score 13 14 def choose_course(self): 15 print('%s choosing course' % self.name) 16 17 class OldboyTeacher(OldboyPeople): 18 def __init__(self,name,age,sex,level): 19 OldboyPeople.__init__(self,name,age,sex) 20 self.level=level 21 22 def score(self,stu,num): 23 stu.score=num 24 25 26 stu1=OldboyStudent('刘二蛋',38,'male') 27 print(stu1.__dict__) 28 29 tea1=OldboyTeacher('egon',18,'male',10) 30 print(tea1.__dict__) 31 32
在子类派生出的新方法中重用父类功能的方式二:super()必须在类中用
1 class Sup: 2 def __init__(self, name): 3 self.name = name 4 5 def test(self): 6 print(self) 7 8 9 class Sub(Sup): 10 # 默认父级的__init__可以被继承过来, 11 # 但是会出现子类对象的属性比父类多 12 def __init__(self, name, salary): 13 super().__init__(name) # 父级有的共性功能通过super()交给父级做 14 self.salary = salary # 子类特有的自己来完成 15 16 # 有继承关系下,只要名字相同,即使参数不同,还是属于同一个方法 17 def test(self, num): 18 super().test() # 使用父级的方法 19 print(num) 20 21 # 外界通过Sub对象来调用test方法,一定找自己的test方法(属性的查找顺序) 22 23 24 # 重点:super() 可以得到调用父级功能的对象,调用者还是子类对象 25 # -- super()只能在子类的方法中使用 26 # -- super()本质 super(子类类名, 当前对象) 27 # -- super().父类普通方法 | super().__init__() | super()能调用父类所有可继承方法
# 在python2中:super(自己的类名,自己的对象)
# 在python3中:super()
# 调用该函数会得到一个特殊的对象,该对象专门用来访问父类中的属性,!!!完全参照mro列表!!!!
# 总结:
# 1. 严格依赖继承的mro列表
# 2. 访问是绑定方法,有自动传值的效果
1 # class OldboyPeople: 2 # school = 'Oldboy' 3 # 4 # def __init__(self,name,age,sex): 5 # self.name = name 6 # self.age = age 7 # self.sex = sex 8 # 9 # class OldboyStudent(OldboyPeople): 10 # def __init__(self, name, age, sex, score=0): 11 # super(OldboyStudent,self).__init__(name,age,sex) 12 # self.score = score 13 # 14 # def choose_course(self): 15 # print('%s choosing course' % self.name) 16 # 17 # class OldboyTeacher(OldboyPeople): 18 # def __init__(self,name,age,sex,level): 19 # super().__init__(name,age,sex) 20 # self.level=level 21 # 22 # def score(self,stu,num): 23 # stu.score=num 24 25 26 # stu1=OldboyStudent('刘二蛋',38,'male') 27 # print(stu1.__dict__) 28 # 29 # tea1=OldboyTeacher('egon',18,'male',10) 30 # print(tea1.__dict__)
4.单继承背景下的属性的查找
在单继承背景下属性的查找优先级:对象->对象的类->父类->父类.....
1 class Foo: 2 def f1(self): 3 print('Foo.f1') 4 5 def f2(self): 6 print('Foo.f2') 7 self.f1() #obj.f1() 8 9 class Bar(Foo): 10 def f1(self): 11 print('Bar.f1') 12 13 obj=Bar() 14 obj.f2() 15 ''' 16 Foo.f2 17 Bar.f1 18 '''
5
# 在多继承背景下属性的查找优先级:
# 如果一个子类继承多个分支(多个分支没有共同继承一个非object的类)
# 此时属性的查找优先级是:对象->对象的类->按照从左往右的顺序一个分支一个分支的找下去
1 2 # # 第四层: 3 # class G: 4 # # x = 'G' 5 # pass 6 # 7 # # 第三层 8 # class E(G): 9 # # x = 'E' 10 # pass 11 # 12 # class F: 13 # # x = 'F' 14 # pass 15 # 16 # # 第二层 17 # class B(E): 18 # # x = 'B' 19 # pass 20 # 21 # class C(F): 22 # # x = 'C' 23 # pass 24 # 25 # class D: 26 # # x = 'D' 27 # pass 28 # 29 # # 第一层 30 # class A(B, C, D): 31 # # x = 'A' 32 # pass 33 # 34 # obj = A() 35 # # obj.x = 111 36 # print(obj.x) 37
#菱形继承问题:
# 新式类 : 广度优先查找,从左往右一个分支一个分支的查找,在最后一个分支才去查找顶级类
# 经典类 : 深度优先查找,从左往右一个分支一个分支的查找,在第一个分支就查找顶级类
1 class G(object): 2 # x = 'G' 3 pass 4 5 # 第三层 6 class E(G): 7 # x = 'E' 8 pass 9 10 class F(G): 11 # x = 'F' 12 pass 13 14 # 第二层 15 class B(E): 16 # x = 'B' 17 pass 18 19 class C(F): 20 # x = 'C' 21 pass 22 23 class D(G): 24 # x = 'D' 25 pass 26 27 # 第一层 28 class A(B, C, D): 29 # x = 'A' 30 pass 31 32 33 obj=A() 34 # obj.x=111 35 print(obj.x) 36 #新式类(广度优先): obj->A->B->E->C-F->D->G->object 37 #经典类(深度优先): obj->A->B->E->G->C-F->D 38 39 # python专门为新式类内置了一个mro的方法,用来查看c3算法的计算结果,结果是?? 40 print(A.mro())