第五章---面向对象---1.继承/2.派生/3.继承的实现原理/4.在子类中重用父类的方法和属性
1.继承:指的是类与类之间的关系,是一种什么是什么的关系,继承的功能是解决代码的重用问题,继承是一种创建新类的方式
python 中新建的类可以继承一个或多个父类(基类或超类)
新建的类称为派生类或子类
对象之间相似的特征-------类
类之间相似的特征 ---- 父类
继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。
1 class ParentClass1: 2 pass 3 4 class ParentClass2: 5 pass 6 7 class SubClass1(ParentClass1): 8 pass 9 10 class SubClass2(ParentClass1,ParentClass2): 11 pass 12 13 # print(SubClass1.__bases__) 14 # print(SubClass2.__bases__) 15 # 16 # # (<class '__main__.ParentClass1'>,) 17 # # (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>) 18 19 20 class Hero: 21 def __init__(self,name,attack,life_value): 22 self.name = name 23 self.attack = attack 24 self.life_value = life_value 25 26 def attack_other(self,enemy): 27 enemy.life_value -= self.attack 28 if enemy.life_value <= 0: 29 print('%s 没有血量,宣布死亡!'% enemy.name) 30 else: 31 print('%s血量剩余%s'% (enemy.name,enemy.life_value)) 32 class HeroDog(Hero): 33 pass 34 35 class HeroPig(Hero): 36 pass 37 38 hero_d = HeroDog('Dog',10,100) 39 hero_p = HeroPig('pig',20,100) 40 41 # hero_d.attack_other(hero_p) 42 43 继承属性查找小练习: 44 45 练习一: 46 class Foo: 47 def f1(self): 48 print('from Foo.f1') 49 def f2(self): 50 print('from Foo.f2') 51 self.f1() 52 53 class Bar(Foo): 54 def f2(self): 55 print('from Bar.f2') 56 57 b1 = Bar() 58 b1.f2() 59 # from Bar.f2 60 b1首先在自己这个对象中找f2(),找不到然后去自己所在的类Bar中去找,找到了输出结果 61 62 练习二: 63 class Foo: 64 def f1(self): 65 print('from Foo.f1') 66 def f2(self): 67 print('from Foo.f2') 68 self.f1() # b.f1() 69 70 class Bar(Foo): 71 def f1(self): 72 print('from Bar.f1') 73 74 b1 = Bar() 75 b1.f2() 76 # from Foo.f2 77 # from Bar.f1 78 # b1首先在自己这个对象中找f2(),找不到然后去自己所在的类Bar中去找, 79 # 仍然找不到就会去Bar的父类Foo中去找,找到了,首先打印的是'from Foo.f2', 80 # 然后会执行self.f1(),由于这个self就是对象b1,所以会继续前面的寻找方式, 81 # 先去自己本身的对象中找,找不到去所在的类,找不到在去类所在的父类!
2.派生:子类可以添加自己的 新属性 数据属性 函数属性
查找顺序:1.对象本身--》2.对象所在的类里面找--》3.父类里面找
1 class Hero: 2 def __init__(self,name,attack,life_value): 3 self.name = name 4 self.attack = attack 5 self.life_value = life_value 6 7 def attack_other(self,enemy): 8 enemy.life_value -= self.attack 9 if enemy.life_value <= 0: 10 print('%s 没有血量,宣布死亡!'% enemy.name) 11 else: 12 print('%s血量剩余%s'% (enemy.name,enemy.life_value)) 13 14 class HeroDog(Hero): 15 camp = 'Dog_camp' 16 def attack_other(self,enemy): 17 print('from HeroDog class') 18 19 class HeroPig(Hero): 20 camp = 'Pig_camp' 21 22 hero_d = HeroDog('Dog',10,100) 23 hero_p = HeroPig('pig',20,100) 24 hero_d.attack_other(hero_p)
3.继承的实现原理: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'>]
0.对象本身优先于子类
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如果继承了多个父类,那么属性的查找方式有两种,
分别是:深度优先和广度优先 (本质按列表顺序来) --》只是一种排序的不同方式
python中类分为两种:1.新式类 2.经典类 (py2中)
1.新式类 (py3 --> 只有新式类)
1 # 在python2中-》 经典类:没有继承object的类,以及他的子类都称之为经典类 2 # class Foo: 3 # pass 4 # 5 # class Bar(Foo): 6 # pass 7 8 # 在python2中-》 新式类:继承了object的类,以及他的子类都称之为经典类 9 # class Foo(object): 10 # pass 11 # 12 # class Bar(Foo): 13 # pass 14 15 # 在python3中-》 新式类:一个类没有继承object类,默认就继承object 16 # class Foo: 17 # pass 18 # print(Foo.__bases__) 19 20 21 # 验证多继承情况下的属性查找 -- # F D B X E C A 新式类 --》 广度优先 22 class A(object): 23 # def test(self): 24 # print('from A') 25 pass 26 27 class B(A): 28 # def test(self): 29 # print('from B') 30 pass 31 32 class C(A): 33 # def test(self): 34 # print('from C') 35 pass 36 37 class D(B): 38 # def test(self): 39 # print('from D') 40 pass 41 42 class E(C): 43 # def test(self): 44 # print('from E') 45 pass 46 47 class F(D,E): 48 # def test(self): 49 # print('from F') 50 pass 51 f1=F() 52 f1.test() 53 print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性 54 # (<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) 55 56 #新式类继承顺序:F->D->B->E->C->A 57 #经典类继承顺序:F->D->B->A->E->C 58 #python3中统一都是新式类 59 #pyhon2中才分新式类与经典类
4.在子类中重用父类的方法和属性
在子类派生出的新的方法中重用父类的方法:有两种实现方式:
方式一:指名道姓(不依赖继承)
Hero.attack_other(self,enemy) # 指名道姓 不依赖继承
Hero.__init__(self,name,attack,life_value) # 指名道姓 不依赖继承
方式二:super() (依赖继承) super() 会从对象的(MRO)列表中找
super(Garen,self).attack_other(enemy) # 依赖继承
super(Garen,self).__init__(name,attack,life_value) # 依赖继承 py2 写法
super().__init__(name,attack,life_value) # py3 写法
1 # 方式一:指名道姓 2 # class Hero: 3 # def __init__(self,name,attack,life_value): 4 # self.name = name 5 # self.attack = attack 6 # self.life_value = life_value 7 # 8 # def attack_other(self,enemy): 9 # enemy.life_value -= self.attack 10 # if enemy.life_value <= 0: 11 # print('%s 没有血量,宣布死亡!'% enemy.name) 12 # else: 13 # print('%s血量剩余%s'% (enemy.name,enemy.life_value)) 14 # 15 # class HeroDog(Hero): 16 # camp = 'Dog_camp' 17 # def attack_other(self,enemy): 18 # Hero.attack_other(self,enemy) # 指名道姓方法,不依赖继承 19 # print('from HeroDog class') 20 # 21 # class HeroPig(Hero): 22 # camp = 'Pig_camp' 23 # 24 # hero_d = HeroDog('Dog',10,100) 25 # hero_p = HeroPig('pig',20,100) 26 # hero_d.attack_other(hero_p) 27 28 29 # 方式一:指名道姓 30 # class Hero: 31 # def __init__(self, name, attack, life_value): 32 # self.name = name 33 # self.attack = attack 34 # self.life_value = life_value 35 # 36 # def attack_other(self, enemy): 37 # enemy.life_value -= self.attack 38 # if enemy.life_value <= 0: 39 # print('%s 没有血量,宣布死亡!' % enemy.name) 40 # else: 41 # print('%s血量剩余%s' % (enemy.name, enemy.life_value)) 42 # 43 # 44 # class HeroDog(Hero): 45 # camp = 'Dog_camp' 46 # 47 # def __init__(self,name,attack,life_value,weapon): 48 # # self.name = name 49 # # self.attack = attack 50 # # self.life_value = life_value 51 # Hero.__init__(self,name,attack,life_value) # 指名道姓方法 52 # 53 # self.weapon = weapon 54 # 55 # def attack_other(self, enemy): 56 # Hero.attack_other(self, enemy) # 指名道姓方法,不依赖继承 57 # print('from HeroDog class') 58 # 59 # hero_d = HeroDog('Dog', 10, 100,'大刀') 60 # print(hero_d.__dict__) 61 62 63 # 方式二:super() (依赖继承) 64 # class Hero: 65 # def __init__(self,name,attack,life_value): 66 # self.name = name 67 # self.attack = attack 68 # self.life_value = life_value 69 # 70 # def attack_other(self,enemy): 71 # enemy.life_value -= self.attack 72 # if enemy.life_value <= 0: 73 # print('%s 没有血量,宣布死亡!'% enemy.name) 74 # else: 75 # print('%s血量剩余%s'% (enemy.name,enemy.life_value)) 76 # 77 # class HeroDog(Hero): 78 # camp = 'Dog_camp' 79 # def attack_other(self,enemy): 80 # super(HeroDog,self).attack_other(enemy) # 依赖继承 81 # # super(HeroDog,self) 这就是父类的对象 82 # print('from HeroDog class') 83 # 84 # class HeroPig(Hero): 85 # camp = 'Pig_camp' 86 # 87 # hero_d = HeroDog('Dog',10,100) 88 # hero_p = HeroPig('pig',20,100) 89 # hero_d.attack_other(hero_p) 90 91 92 # 方式二:super() (依赖继承) 93 # class Hero: 94 # def __init__(self, name, attack, life_value): 95 # self.name = name 96 # self.attack = attack 97 # self.life_value = life_value 98 # 99 # def attack_other(self, enemy): 100 # enemy.life_value -= self.attack 101 # if enemy.life_value <= 0: 102 # print('%s 没有血量,宣布死亡!' % enemy.name) 103 # else: 104 # print('%s血量剩余%s' % (enemy.name, enemy.life_value)) 105 # 106 # 107 # class HeroDog(Hero): 108 # camp = 'Dog_camp' 109 # 110 # def __init__(self,name,attack,life_value,weapon): 111 # # super(HeroDog,self).__init__(name,attack,life_value) 112 # super().__init__(name, attack, life_value) # python可以这样简写 113 # self.weapon = weapon 114 # 115 # def attack_other(self, enemy): 116 # Hero.attack_other(self, enemy) # 指名道姓方法,不依赖继承 117 # print('from HeroDog class') 118 # 119 # hero_d = HeroDog('Dog', 10, 100,'大刀') 120 # print(hero_d.__dict__) 121 122 #-------------------------------------------------------- 123 # A没有继承B,但是A内super会基于C.mro()继续往后找 124 class A: 125 def f1(self): 126 print('from A') 127 super().f1() 128 129 class B: 130 def f1(self): 131 print('from B') 132 133 class C(A,B): 134 pass 135 # print(C.mro()) 136 # [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>] 137 138 c = C() 139 c.f1() 140 # from A 141 # from B