python-继承与重用
Posted cook
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python-继承与重用相关的知识,希望对你有一定的参考价值。
什么是继承?
继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类或超类,新建的类称为派生类或子类。子类会“”遗传”父类的属性,从而解决代码重用问题(比如练习7中Garen与Riven类有很多冗余的代码)
单继承与多继承
class ParentClass_one: #定义父类 pass class ParentClass_two: #定义父类 pass class SubClass_one(ParentClass_one): #单继承,基类是ParentClass1,派生类是SubClass pass class SubClass_two(ParentClass_one,ParentClass_two): #python支持多继承,用逗号分隔开多个继承的类 pass
经典类与新式类
- 只有在python2中才分新式类和经典类,python3中统一都是新式类
- 在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类
- 在python2中,显式地声明继承object的类,以及该类的子类,都是新式类
- 在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类
继承与抽象
- 继承描述的是子类与父类之间的关系,是一种什么是什么的关系。要找出这种关系,必须先抽象再继承,抽象即抽取类似或者说比较像的部分。抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)
- 继承是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类
继承与重用性
在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时,则不需要从头开始写一个类B,只需要通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用
class Hero: def __init__(self,nickname,aggressivity,life_value): self.nickname=nickname self.aggressivity=aggressivity self.life_value=life_value def move_forward(self): print(\'%s move forward\' %self.nickname) def move_backward(self): print(\'%s move backward\' %self.nickname) def move_left(self): print(\'%s move forward\' %self.nickname) def move_right(self): print(\'%s move forward\' %self.nickname) def attack(self,enemy): enemy.life_value-=self.aggressivity class Garen(Hero): pass class Riven(Hero): pass g=Garen(\'草丛伦\',100,300) r=Riven(\'锐雯雯\',57,200) print(g.life_value) r1.attack(g) print(g.life_value) \'\'\' 运行结果 243 \'\'\' ps:像g.life_value之类的属性引用,会先从实例中找life_value然后去类中找,然后再去父类中找...直到最顶级的父类。
派生
子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准。
class Riven(Hero): camp=\'Noxus\' def __init__(self,nickname,aggressivity,life_value,skin): Hero.__init__(self,nickname,aggressivity,life_value) #调用父类功能 self.skin=skin #新属性 def attack(self,enemy): #在自己这里定义新的attack,不再使用父类的attack,且不会影响父类 Hero.attack(self,enemy) #调用功能 print(\'from riven\') def fly(self): #在自己这里定义新的 print(\'%s is flying\' %self.nickname) r=Riven(\'锐雯雯\',57,200,\'比基尼\') r.fly() print(r.skin) \'\'\' 运行结果 锐雯雯 is flying 比基尼 \'\'\'
组合与重用性
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
class Equip: #武器装备类 def fire(self): print(\'release Fire skill\') class Riven: #英雄Riven的类,一个英雄需要有装备,因而需要组合Equip类 camp=\'Noxus\' def __init__(self,nickname): self.nickname=nickname self.equip=Equip() #用Equip类产生一个装备,赋值给实例的equip属性 r=Riven(\'锐雯雯\') print(r.equip.fire()) #可以使用组合的类产生的对象所持有的方法 \'\'\' release Fire skill \'\'\'
组合与继承
- 继承的方式:通过继承建立了派生类与基类之间的关系,它是一种\'是\'的关系,比如白马是马,人是动物。当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人
- 组合的方式:用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...
ps:当类之间有显著不同,并且较小的类是较大的类所需要的组件时,使用组合比较好
class People: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex class Course: def __init__(self,name,period,price): self.name=name self.period=period self.price=price def tell_info(self): print(\'<%s %s %s>\' %(self.name,self.period,self.price)) class Teacher(People): def __init__(self,name,age,sex,job_title): People.__init__(self,name,age,sex) self.job_title=job_title self.course=[] self.students=[] class Student(People): def __init__(self,name,age,sex): People.__init__(self,name,age,sex) self.course=[] jack=Teacher(\'jack\',18,\'male\',\'computer teacher\') s=Student(\'tom\',18,\'female\') python=Course(\'python\',\'3mons\',3000.0) linux=Course(\'python\',\'3mons\',3000.0) #为老师jack和学生s1添加课程 jack.course.append(python) jack.course.append(linux) s.course.append(python) #为老师jack添加学生s jack.students.append(s) #使用 for obj in jack.course: obj.tell_info()
继承实现原理
在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D),如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性,如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先
def test(self): print(\'from A\') class B(A): def test(self): print(\'from B\') class C(A): def test(self): print(\'from C\') class D(B): def test(self): print(\'from D\') class E(C): def test(self): print(\'from E\') class F(D,E): # def test(self): # print(\'from F\') pass f1=F() f1.test() print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性 #新式类继承顺序:F->D->B->E->C->A #经典类继承顺序:F->D->B->A->E->C #python3中统一都是新式类 #pyhon2中才分新式类与经典类
Python实现继承
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列表并遵循如下三条准则:
- 子类会先于父类被检查
- 多个父类会根据它们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类
子类调用父类的方法
方法一:指名道姓,即父类名.父类方法()
class Vehicle: #定义交通工具类 Country=\'China\' def __init__(self,name,speed,load,power): self.name=name self.speed=speed self.load=load self.power=power def run(self): print(\'开动啦...\') class Subway(Vehicle): #地铁 def __init__(self,name,speed,load,power,line): Vehicle.__init__(self,name,speed,load,power) self.line=line def run(self): print(\'地铁%s号线欢迎您\' %self.line) Vehicle.run(self) line13=Subway(\'中国地铁\',\'180m/s\',\'1000人/箱\',\'电\',13) line13.run()、
方法二:super()
class Vehicle: #定义交通工具类 Country=\'China\' def __init__(self,name,speed,load,power): self.name=name self.speed=speed self.load=load self.power=power def run(self): print(\'开动啦...\') class Subway(Vehicle): #地铁 def __init__(self,name,speed,load,power,line): #super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self) super().__init__(name,speed,load,power) self.line=line def run(self): print(\'地铁%s号线欢迎您\' %self.line) super(Subway,self).run() class Mobike(Vehicle):#摩拜单车 pass line13=Subway(\'中国地铁\',\'180m/s\',\'1000人/箱\',\'电\',13) line13.run()
以上是关于python-继承与重用的主要内容,如果未能解决你的问题,请参考以下文章