继承
什么是继承
继承就是新建类的一种方式,新建的类我们称为子类或者派生类;被继承的类我们称为父类或者基类,子类可以使用父类中的属性或者方法
为什么要用继承
1、类解决了对象与对象之间的代码冗余问题
2、继承解决的是类与类之间的代码冗余问题
如何使用继承
1、新式类:继承了object类的子子孙孙类都是新式类
2、经典类:没有继承了object类的子子孙孙类都是经典类
注:经典类和新式类只有在python2中有区分,python3中只有新式类
3、代码演示(学生选课为例)
1 # 父类,公共类 2 class People(): 3 school = 'SH' 4 5 def __init__(self, name, age, gender): 6 self.name = name 7 self.age = age 8 self.gender = gender 9 10 # 学生类 11 class Student(People): 12 13 def __init__(self, name, age, gender, course=None): 14 if course is None: 15 course = [] 16 People.__init__(self, name, age, gender) 17 self.courses = course 18 19 def choose_course(self, course): 20 self.courses.append(course) 21 print('%s 选课成功 %s' % (self.name, self.courses)) 22 23 24 stu = Student('tony', 19, 'male') 25 26 # teacher类 27 class Teacher(People): 28 29 def __init__(self, name, age, gender, level): 30 self.level = level 31 People.__init__(self, name, age, gender) 32 33 def score(self, stu_obj, score): 34 stu_obj.score = score # 给学生打分 35 print('%s给%s打了%s分' % (self.name, stu_obj.name, score)) 36 37 38 tea = Teacher('tom', 19, 'male', 10) 39 print(tea.name) 40 print(tea.level)
单继承下属性查找
1、代码练习
class Foo: def f1(self): print('Foo.f1') def f2(self): # print('Foo.f2') self.f1() class Bar(Foo): def f1(self): print('Bar.f1') obj = Bar() # {} obj.f2()
# 结果
# Foo.f2
# Bar.f1
2、练习
class Foo: def __f1(self): # _Foo__f1() print('Foo.f1') def f2(self): # print('Foo.f2') self.__f1() # _Foo__f1() class Bar(Foo): def __f1(self): # # _Bar__f1() print('Bar.f1') obj = Bar() # {} obj.f2()
多继承下的属性查找
1、新式类中是按照广度优先查找
2、经典类:是按照深度优先查找
3、练习
class A(object): def test(self): print('from A') 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 f1 = F() f1.test()
super()和mro()列表
super()使用
class People(): school = 'SH' def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender class Teacher(People): def __init__(self, name, age, gender, level): self.level = level super().__init__(name, age, gender)
mro()列表
练习1
class A: def test(self): print('from A.test') super().test() class B: def test(self): print('from B') class C(A, B): pass c = C() c.test()
练习2
class B: def test(self): print('B---->test') def aaa(self): print('B---->aaa') class A: def test(self): print('A---->test') super().aaa() class C(A, B): def aaa(self): print('C----->aaa') c = A() # c.test() print(A.mro())
注:当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)
继承原理
python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如
>>> F.mro() #等同于F.__mro__ [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。 而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
父类限制子类的行为
class Animal(): def speak(self): raise Exception('必须实现speak') class People(Animal): def speak(self): pass