Day 5-2 类的继承和派生,重用
Posted 大橡皮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day 5-2 类的继承和派生,重用相关的知识,希望对你有一定的参考价值。
类的继承
派生
在子类中重用父类
组合
定义:
继承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题.
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可以成为基类或超类,新建的类称为派生类或子类.
1 # 我们定义的2个英雄都有一些相似的特征和技能.都属于英雄类,那么我们就可以定义个英雄类,然后让英雄继承英雄类的特征和技能 2 3 class Hero: 4 def __init__(self, name, life_value, aggressivity): 5 self.name = name 6 self.life_value = life_value 7 self.aggressivity = aggressivity 8 9 def attck(self,enemy): 10 enemy.life_value -= self.aggressivity 11 12 13 class Garen(Hero): 14 pass 15 16 17 class Riven(Hero): 18 pass 19 20 21 print(Garen.__bases__) # 查看Graren的父类. 22 g1 = Garen("草丛伦", 100, 50) 23 r1 = Riven("兔女郎", 80, 60) 24 print(r1.life_value) 25 # A, 我们通过Garen这个类,来产生一个对象g1.但是Garen这个类中,我们并未定义__init__方法.但是我们也定义成功了,并没有报错.为什么呢? 26 # B, 因为Garen这个类继承了Hero这个父类中的数据属性和函数属性.
提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
派生
当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。简单的来说,派生就是子类自己定义自己独有的特征或方法.
继承的实现原理
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‘>]
所有父类的MRO列表并遵循如下三条准则:
- 子类会先于父类被检查
- 多个父类会根据它们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类
继承的查找:
1 #验证多继承情况下的属性查找 2 3 class A: 4 # def test(self): 5 # print(‘from A‘) 6 pass 7 8 class B(A): 9 # def test(self): 10 # print(‘from B‘) 11 pass 12 13 class C(A): 14 # def test(self): 15 # print(‘from C‘) 16 pass 17 18 class D(B): 19 # def test(self): 20 # print(‘from D‘) 21 pass 22 23 class E(C): 24 # def test(self): 25 # print(‘from E‘) 26 pass 27 28 class F(D,E): 29 # def test(self): 30 # print(‘from F‘) 31 pass 32 33 34 #F,D,B,E,C,A 35 36 print(F.mro()) 37 # f=F() 38 # f.test()
在PY3中,都是新式类,没有经典类了.
经典类:在py2中.定义一个类.class Her0().如果括号里,没有继承基类object.它就是一个经典类.如果class Hero(object),那么就是一个新式类
py3中.如果一个类没有继承,那么默认继承object.
子类中重用父类
方式1,指名道姓的方式.(不依赖与继承)
1 class Hero: 2 def __init__(self, name, life_value, aggressivity): 3 self.name = name 4 self.life_value = life_value 5 self.aggressivity = aggressivity 6 7 def attck(self,enemy): 8 enemy.life_value -= self.aggressivity 9 10 11 class Garen(Hero): 12 13 def __init__(self, name, life_value, aggressivity, weapon): 14 Hero.__init__(self,name, life_value, aggressivity) # 指名道姓的调用父类中的方法. 15 self.weapon = weapon 16 17 def attck(self,enemy): 18 Hero.attck(self,enemy) # 指名道姓的调用父类中的方法. 19 print("in Garen class") 20 21 22 class Riven(Hero): 23 pass 24 25 26 27 g1 = Garen("草丛伦", 100, 50,"黑切") 28 29 print(g1.__dict__) # 查看g1的dict中,已经有了黑切.
方式2,super() (依赖于继承)
1 # 方式2, super() 依赖继承 2 class Hero: 3 def __init__(self, name, life_value, aggressivity): 4 self.name = name 5 self.life_value = life_value 6 self.aggressivity = aggressivity 7 8 def attck(self,enemy): 9 enemy.life_value -= self.aggressivity 10 11 12 class Garen(Hero): 13 14 def __init__(self, name, life_value, aggressivity, weapon): 15 # Hero.__init__(self,name, life_value, aggressivity) # 指名道姓的调用父类中的方法. 16 # super(Garen,self).__init__(name,life_value,aggressivity) 17 super().__init__(name,life_value,aggressivity) # 简写 18 self.weapon = weapon 19 20 def attck(self,enemy): 21 # Hero.attck(self,enemy) # 指名道姓的调用父类中的方法. 22 # super(Garen,self).attck(enemy) # super方法,括号里的Garen的位置是子类的名称,self是生成对象的名称.后面是调用的方法. 23 super().attck(enemy) # 在py3中,可以简写成这样. 24 print("in Garen class") 25 26 27 28 class Riven(Hero): 29 pass 30 31 32 33 g1 = Garen("草丛伦", 100, 50,"黑切") 34 r1 = Riven("兔女郎瑞文", 80,50) 35 g1.attck(r1) 36 print(r1.life_value) 37 38 print(g1.__dict__) # 查看g1的dict中,已经有了黑切.
1 class A: 2 def f1(self): 3 print("from A") 4 super().f1() #在这里调用super().f1()的时候.基于的是C这个类的mro列表进行查找的.并不是说,在A类中调用super,就是在A类中,查找A的父类中的f1方法 5 6 class B: 7 def f1(self): 8 print("from B") 9 10 class C(A,B): 11 pass 12 13 print(C.mro()) 14 i = C() 15 i.f1() # 查找f1的是,都是基于对象i来进行查找的.如果i里没有f1方法.那么就去它的类中查找,如果类中没有,就去类所继承的父类中按照mro列表查找.
组合
软件重用的重要方式除了继承之外还有另外一种方式,即:组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合.
组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同,
1.继承的方式
通过继承建立了派生类与基类之间的关系,它是一种‘是‘的关系,比如白马是马,人是动物。
当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人
2.组合的方式
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...
1 class People: 2 """定义人类""" 3 school = "luffycity" 4 def __init__(self, name, age, sex): 5 self.name = name 6 self.age = age 7 self.sex =sex 8 9 class Teacher(People): 10 """定义一个人教师类""" 11 def __init__(self, name, age, sex, level, salary): 12 super().__init__(name, age, sex) 13 self.level = level 14 self.salary = salary 15 16 def teach(self): 17 print("%s is teaching" % self.name) 18 19 20 class Students(People): 21 """定义一个学生类""" 22 def __init__(self, name, age, sex, grade): 23 super().__init__(name, age, sex) 24 self.grade = grade 25 26 def learn(self): 27 print("%s is learning" % self.name) 28 29 30 class Course: 31 """定义一个课程类""" 32 def __init__(self, course_name, course_price, course_period): 33 self.course_name = course_name 34 self.course_price = course_price 35 self.course_period = course_period 36 37 def tell_info(self): 38 print("课程名:%s, 课程价格:%s, 课程周期:%s" % (self.course_name, self.course_price, self.course_period)) 39 40 41 42 class Bron_date: 43 """定义一个生日类""" 44 def __init__(self, year, mon, day): 45 self.year = year 46 self.mon = mon 47 self.day = day 48 def tell_info(self): 49 print("生日:%s年%s月%s日" % (self.year, self.mon, self.day)) 50 51 # t1 = Teacher("alex", 22, "男", "一级", 100000) 52 #生成一个stu1的学生对象 53 stu1 = Students("杰克", 18, "男", "python全栈开发") 54 #生成一个python的课程对象 55 python = Course("python", 8999, "6mons") 56 # 把python对象赋给stu1.course.学生stu1有课程.这里就是组合 57 stu1.course = python 58 #输入sut1的课程信息
以上是关于Day 5-2 类的继承和派生,重用的主要内容,如果未能解决你的问题,请参考以下文章