继承
继承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题,
继承是一种创建新类的方式,在python中新建的类可以继承一个或多个父类,父类可称为基类或者超类,新建的类称为派生类或子类。
python中类的继承分为:单继承和多继承
classBiology: # 定义一个父类
passclassAnimal: # 定义一个父类
passclassPerson(Biology): # 单继承,基类是Biology, 派生类是person
passclassDog(Biology, Animal): # 多继承,用逗号隔开多个基类
pass
查看继承:
# 可通过类名.__bases__查看所有继承的父类,类名.__base__只查看从左到右继承的第一个父类
print(Dog.__base__)
#print(Dog.__bases__)
# (, )
经典类和新式类:
1.只有在python2中才分新式类和经典类,python3中统一都是新式类
2.在python2中,没有声明继承object类的类,以及该类的子类,都是经典类
3.在python2中,声明继承object的类,以及该类的子类,都是新式类
4.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类
继承与抽象:
抽象即抽取类似或比较像的部分。
抽象分为两个层次:
1.把多个对象中比较像的部门抽取成类
2.把多个类中比较像的部门抽取成父类
抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)
继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构
抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类
继承与重用性
class Hero(object): #英雄的类
def __init__(self, name, camp, money, life_value, aggressivity,
defensive):#类的属性包括:英雄的名字,阵营,资产,生命值,攻击力,防御力
self.name =name
self.camp=camp
self.money=money
self.life_value=life_value
self.aggressivity=aggressivity
self.defensive=defensivedef attack(self, enemy): #类的技能,英雄具有攻击技能
enemy.life_value -=self.aggressivityclass Garen(Hero): #Garen类继承Hero类
pass
class Riven(Hero): #Riven类继承Hero类
passgaren1= Garen("德玛西亚之力", "德玛西亚", 1000, 300, 60, 40) #实例化Garen类时,Hero类中定义的属性直接使用
riven1 = Riven("锐萌萌", "诺克萨斯", 1000, 280, 70, 30)
garen1.attack(riven1)#Garen类实力话的对象可以直接使用Hero类中定义的方法
print(garen1.life_value)print(riven1.life_value)
通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用。
派生
class Garen(Hero): #Garen类继承Hero类
def attack(self, enemy): #子类可以重新定义攻击技能,不会改变父类的攻击方法
enemy.life_value -= (self.aggressivity -enemy.defensive)def life_reply(self): #子类可以新加一个生命恢复技能
self.life_value += 20
属性查找顺序
先从自己内部找,然后再去类里找,最后再去父类中找。
父类中查找的顺序
经典类:按继承的类的顺序从左到右深度优先
新式类:按继承的类的顺序从左到右广度优先
对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。而这个MRO列表的构造是通过一个C3线性化算法来实现的。
classA(object):deftest(self):print("from a")classB(A):pass
#def test(self):
#print("from b")
classC(A):pass
#def test(self):
#print("from c")
classD(B):pass
#def test(self):
#print("from d")
classE(C):pass
#def test(self):
#print("from e")
classF(A):pass
#def test(self):
#print("from f")
classH(D,E,F):passh1=H()
h1.test()#from a
print(H.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性#(, , , , , , , )
子类里调用父类的方法
在子类派生出的新方法中,往往需要重用父类的方法,我们有两种方式实现
一、指名道姓,即父类名.父类方法()
二、super()
class Hero(object): #英雄的类
def __init__(self, name, camp, money, life_value, aggressivity,
defensive):#类的属性包括:英雄的名字,阵营,资产,生命值,攻击力,防御力
self.name =name
self.camp=camp
self.money=money
self.life_value=life_value
self.aggressivity=aggressivity
self.defensive=defensivedef attack(self, enemy): #类的技能,英雄具有攻击技能
enemy.life_value -=self.aggressivityclass Garen(Hero): #Garen类继承Hero类
def __init__(self, name, camp, money, life_value, aggressivity, defensive, sex):#Hero.__init__(self, name, camp, money, life_value, aggressivity, defensive) # 指名道姓
#super(Garen, self).__init__(name, camp, money, life_value, aggressivity, defensive) # python2
super().__init__(name, camp, money, life_value, aggressivity, defensive) #python3中 super() = super(Garen, self)
self.sex =sexdef attack(self, enemy): #子类可以重新定义攻击技能,不会改变父类的攻击方法
enemy.life_value -= (self.aggressivity -enemy.defensive)def life_reply(self): #子类可以新加一个生命恢复技能
self.life_value += 20
class Riven(Hero): #Riven类继承Hero类
passgaren1= Garen("德玛西亚之力", "德玛西亚", 1000, 300, 60, 40, "man")
riven1= Riven("锐萌萌", "诺克萨斯", 1000, 280, 70, 30)
garen1.attack(riven1)#Garen类实力话的对象可以直接使用Hero类中定义的方法
print(garen1.life_value)print(riven1.life_value)
两种方式的区别:方式一时跟继承没有关系的,而方式二的super()是依赖与继承的,并且即使没有直接继承关系,super()仍然会按照mro继续往后查找
#A没有继承B,但是A内super会基于C.mro()继续往后找
classA:deftest(self):
super().test()classB:deftest(self):print('from B')classC(A,B):passc=C()
c.test()#打印结果:from B
print(C.mro())#[, , , ]
组合
组合指的是类与类之间的关系,是一种什么“有”什么的关系,在一个类中以另一个类的对象作为数据属性,称为类的组合
class Arms: #定义一个武器类
def __init__(self, aggressivity): #定义武器攻击力属性
self.aggressivity =aggressivityclass Hero: #定义一个英雄的类
role = "hero" #定义一个公同属性角色
def __init__(self, camp, life_value, aggressivity, defensive,
arm=0): #定义一个自定义值的属性函数 属性包括生命值,攻击力,防御,和武器属性,默认是0,传入武器后改变
self.camp =camp
self.life_value=life_value
self.aggressivity=aggressivity
self.defensive=defensive
self.arm= [] #装备的武器列表
def attack(self, target): #攻击技能
aggressvity =self.aggressivityif self.arm: #判断是否装备了武器
for i inself.arm:
aggressvity+= i.aggressivity #将武器的攻击力加上
target.life_value-= (aggressvity -target.defensive)
garen= Hero("Demarcia", 100, 60, 30) #实例化一个盖伦对象,并传入英雄的生命值,攻击,防御,武器
rivan = Hero("xx", 90, 70, 20) #实例化一个锐雯对象,并传入英雄的生命值,攻击,防御,武器
big_sword = Arms(60) #实例化武器的类,生成一个名叫大剑的武器
garen.arm.append(big_sword) #给盖伦装备装大剑
garen.attack(rivan) #盖伦攻击锐雯一次
print(rivan.life_value)
总结:
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好