发布时间:2020/07/15 作者:天马行空 阅读(1748)
一、类的继承性
1.1、object类
当我们定义一个类,使用类似class ABC()这样的形式时,父类括号中看起来是空的,但实际上,此时的ABC类并不是没有父类,而是默认继承Python的根类:object类。
因此,object类可以看做是Python所有类的“祖先”。
Python的内置方法dir( )
dir( )的语法规则是dir(o),其中o是一个类,dir(o)返回的是类o所有的方法。
class FelidAnimal():
pass
print("FelidAnimal的变量有{}" .format(FelidAnimal.__dict__))
print("======")
print("FelidAnimal的方法有{}" .format(dir(FelidAnimal)))我们发现,即便是类体中什么都没有定义,类还是有很多变量和方法,并且这些变量和方法都是魔法变量和魔法方法。
它们都是继承自FelidAnimal的父类,也就是object类。
object类中一个比较重要的方法__str__()方法(注意str前后各有两个英文下划线)。__str__方法定义了当print(实例名)时,打印的实例的信息。
1.2、继承
类的继承性是指当前类能够保留父类的变量和方法的特性。
使用构造函数定义了一个具有皮毛、身高和体重的猫科动物类,代码如下。
class FelidAnimal(): def __init__(self, fur, height, weight): self.fur = fur self.height = height self.weight = weight
然后还定义了一个具有姓名、年龄、皮毛、身高和体重的猫类,代码如下:
class Cat(): def __init__(self, name, age, fur, height, weight): self.name = name self.age = age self.fur = fur self.height = height self.weight = weight
可以想到这样两件事情:一是猫类和猫科动物类有三个共有的实例变量fur、height和weight;二是猫类比猫科动物类多两个实例变量name和age。
对于这种关系,我们就可以定义父类和子类关系,用类的继承性来处理。
class FelidAnimal():
def __init__(self, fur, height, weight):
self.fur = fur
self.height = height
self.weight = weight
class Cat(FelidAnimal):
def __init__(self, name, age, fur, height, weight):
super().__init__(fur, height, weight)
self.name = name
self.age = age
tom_cat = Cat("Tom", 2, "black", 0.5, 2.0)
print("Tom的毛发颜色是{}".format(tom_cat.fur))
首先定义了FelidAnimal类,然后定义了Cat类,Cat类继承自FelidAnimal类。
这时,称FelidAnimal是Cat的父类,Cat是FelidAnimal的子类。
Python规定super( )用来指代当前类的父类。因此在Cat类中,super( )就是指父类FelidAnimal。
受保护的属性
定义属性时,在属性名前面放置一个下划线,就表示这个属性是受保护属性。比如将__fur改成_fur,它就成为了一个受保护的属性。
受保护属性的特点介于私有属性和公有属性之间:
它不能在类外直接访问到。
它可以被子类继承。
子类自动获得父类的公有、受保护的类变量、静态方法、实例方法和类方法。对于父类的私有属性及方法,子类不能继承。
class FelidAnimal():
leg_number = 4
def __init__(self, fur, height, weight):
self.__fur = fur
self.__height = height
self.__weight = weight
@staticmethod
def __change_weight(x):
new_weight = x + 0.1
return new_weight
def eat(self):
print("正在吃东西...")
self.__weight = self.__change_weight(self.__weight)
print("体重增长了0.1,变成了{}".format(self.__weight))
class Cat(FelidAnimal):
def __init__(self, name, age, fur, height, weight):
super().__init__(fur, height, weight)
self.__name = name
self.__age = age
tom_cat = Cat("Tom", 2, "black", 0.5, 2.0)
tom_cat.eat()
在猫科动物类里面定义了一个静态方法__change_weight和实例方法eat,其中eat实例方法调用了__change_weight静态方法。
静态方法__change_weight是个私有方法,用于辅助完成增加实例的体重(__weight)的功能。它不能被外界直接调用,而只有当吃了东西(调用eat方法)之后,体重才会增加。
当猫类继承猫科动物类的时候,它也自动获取了eat()方法。我们使用猫类构造了一个实例tom_cat,这个实例也就能够调用实例方法eat()了。
二、类的多态性
2.1、重写
多态性是指子类与父类具有不同变量和功能的特性。发生多态性要有两个前提条件:第一,多态性是发生在父类和子类之间;第二,多态性发生的基础是子类重写父类变量或者父类方法。
class FelidAnimal():
leg_number = 4
def __init__(self, fur, height, weight):
self.fur = fur
self.height = height
self.weight = weight
@staticmethod
def change_weight(x):
new_weight = x + 0.1
print("体重增长0.1")
return new_weight
def eat(self):
print("正在吃东西...")
self.weight = self.change_weight(self.weight)
print("体重变成了{}" .format(self.weight))
class Cat(FelidAnimal):
def __init__(self, name, age, fur, height, weight):
super().__init__(fur, height, weight)
self.name = name
self.age = age
@staticmethod
def change_weight(x):
new_weight = x + 0.2
print("体重增长0.2")
return new_weight
tom_cat = Cat("Tom", 2, "black", 0.5, 2.0)
tom_cat.eat()
在FelidAnimal类中定义了change_weight方法。Cat类继承了FelidAnimal类,如果不发生多态,Cat实例tom_cat调用eat方法时会最终触发FelidAnimal的change_weight方法;
现在我们在Cat类中也定义了change_weight方法,这就意味着子类Cat中的change_weight方法和父类FelidAnimal类中的change_weight方法不再是同一个,使用tom_cat.eat时最终触发的就是子类Cat中的change_weight方法。这就是类的多态性。
练习:重写__str__方法
class Student():
def __init__(self, name, school):
self.__name = name
self.__school = school
def __str__(self):
# 定义打印的信息
information = "这是一个学生实例,姓名为{},学校为{}".format(self.__name, self.__school)
# 返回打印的信息
return information
tom_student = Student("Tom", "小象学院")
print(tom_student)
class Student()的声明中,括号里是空的,表示它默认继承Python的基类object。通过def __str__(self)这段代码,子类重写了object类中已经定义的这个魔法方法。
当Student类的实例tom_student被传做print函数的参数,进行信息打印的时候,print函数其实就是调用了传给它的这个参数,也就是tom_student的__str__()方法,打印出__str__()方法return的字符串内容。于是,我们就看到了自己在__str__()中定义的字符串内容被输出了。
2.2、类型检查
在Python中判断实例归属的时候也是这样。Python使用isinstance(s, c)来判断某个实例是否属于某个类,其中s是实例名称,c是类名称。如果s属于c,则函数返回True,否则,返回False。
class FelidAnimal():
leg_number = 4
def __init__(self, fur, height, weight):
self.__fur = fur
self.__height = height
self.__weight = weight
@staticmethod
def change_weight(x):
new_weight = x + 0.1
return new_weight
def eat(self):
print("正在吃东西...")
self.__weight = self.change_weight(self.__weight)
print("体重增长了0.1,变成了{}".format(self.__weight))
class Cat(FelidAnimal):
def __init__(self, name, age, fur, height, weight):
super().__init__(fur, height, weight)
self.__name = name
self.__age = age
tom_cat = Cat("Tom", 2, "black", 0.5, 2.0)
print(isinstance(tom_cat, Cat))
print(isinstance(tom_cat, FelidAnimal))
isinstance(tom_cat, Cat)和isinstance(tom_cat, FelidAnimal)返回的值都是True,说明tom_cat既属于猫类,又属于猫科动物类。
利用isinstance(s, c)判断实例s是否属于类c的操作叫做类型检查。还有一种比较常见的类型检查是issubclass(c1,c2),它能够用来判断类c1是否是类c2的子类。
class FelidAnimal(): leg_number = 4 def __init__(self, fur, height, weight): self.__fur = fur self.__height = height self.__weight = weight class Cat(FelidAnimal): def __init__(self, name, age, fur, height, weight): super().__init__(fur, height, weight) self.__name = name self.__age = age print(issubclass(Cat,FelidAnimal))

三、英雄归来
现在利用这些知识来模拟网上很火的游戏王者荣耀。
为了实现起来简单一些,我们定义了英雄类作为父类,它的子类有法师类、射手类和坦克类。他们有两个基本的实例变量:姓名和经验值。


3.1、定义英雄类
首先定义英雄类,在定义构造方法时,我们应该有两个基本实例变量的参数:姓名(name)和经验值(experience)。
class Hero(): def __init__(self, name, experience): self.name = name self.experience = experience self.level = self.experience // 100 self.health = 1000 + (self.level*100) self.physical_attack = 150 + (self.level*20) self.physical_armor = 50 + (self.level*10) self.magic_attack = 0 self.magic_armor = 50 + (self.level*20) def attack(self, enemy): pass def level_up(self, value): pass def die(self): pass def hunt(self): pass def match_fight(self): pass class Magician(Hero): pass class Shooter(Hero): pass class Tank(Hero): pass
3.1、定义三个子类
现在定义法师类、射手类、坦克类三个Hero的子类。
法师类需要重写英雄类的魔法攻击属性(magic_attack),基础值修改为80,每level增长60(当前魔法攻击即为80 + level * 60)。
射手类需要重写英雄类的物理攻击属性(physical_attack),基础值修改为200,每level增长50。
坦克类需要重写英雄类的血量(health,基础值修改为2000,每level增长200)、物理护甲(physical_armor,基础值修改为80,每level增长20)和魔法护甲(magic_armor,基础值修改为80,每level增长30)。

class Hero(): def __init__(self, name, experience): self.name = name self.experience = experience self.level = self.experience // 100 self.health = 1000 + (self.level*100) self.physical_attack = 150 + (self.level*20) self.physical_armor = 50 + (self.level*10) self.magic_armor = 50 + (self.level*20) self.magic_attack = 0 def attack(self, enemy): pass def level_up(self, value): pass def die(self): pass def hunt(self): pass def match_fight(self): pass class Magician(Hero): def __init__(self, name,experience): super().__init__(name, experience) self.magic_attack = 80 + (self.level*60) class Shooter(Hero): def __init__(self, name, experience): super().__init__(name, experience) self.physical_attack = 200 + (self.level*50) class Tank(Hero): def __init__(self, name,experience): super().__init__(name, experience) self.health = 2000 + (self.level*200) self.physical_armor = 80 + (self.level*20) self.magic_armor = 80 + (self.level*30)
我们分别定义Magician类、Shooter类和Tank类。其中,在Magician类中重写了魔法攻击实例变量;在Shooter类里面重写了物理攻击力实例变量;在Tank类里面重写了血量、物理护甲和魔法护甲三个实例变量。
3.3、英雄的实例方法
class Hero():
def __init__(self, name, experience):
'''
实例构造方法
传入参数
name:名称
experience:经验值
主要功能
属性初始化操作。根据输入的经验值,计算与该经验值对应的
级别、血量、物理攻击、物理防御、魔法攻击、魔法防御值。
'''
self.name = name
self.experience = experience
self.level = self.experience // 100
self.health = 1000 + (self.level*100)
self.physical_attack = 150 + (self.level*20)
self.physical_armor = 50 + (self.level*10)
self.magic_armor = 50 + (self.level*20)
self.magic_attack = 0
def attack(self, enemy):
'''
攻击方法
传入参数
enemy:被攻击的实例
主要功能
分别计算物理伤害及魔法伤害,并将enemy的血量降低相应的伤害值。
'''
# 物理伤害等于当前实例物理攻击能力减敌人物理防御能力
# 如果攻击能力低于防御能力,物理伤害为0
physical_hurt = 0 if self.physical_attack < enemy.physical_armor else (self.physical_attack - enemy.physical_armor)
# 魔法伤害等于当前实例魔法攻击能力减敌人魔法防御能力
# 如果攻击能力低于防御能力,魔法伤害为0
magic_hurt = 0 if self.magic_attack < enemy.magic_armor else (self.magic_attack - enemy.magic_armor)
# 根据伤害能力,设置enemy的血量为原血量减掉伤害值
enemy.health = enemy.health - physical_hurt - magic_hurt
print("{}攻击了{},一共造成{}点伤害。".format(self.name, enemy.name, (physical_hurt + magic_hurt)))
def level_up(self, value):
'''
升级方法
传入参数
value:增加的经验值
主要功能
将当前实例的经验值增加value,并根据新的经验值计算对应的级别。
如果此次经验值增加导致了升级,调用实例构造方法重新计算新的级别、血量及各攻击和防御能力。
'''
# 增加经验值
self.experience = self.experience + value
# 根据新的经验值计算级别
now_level = self.experience // 100
# 如果新计算的级别比原来的级别高,打印恭喜信息,并调用实例构造方法重新计算各属性
if now_level > self.level:
print("恭喜{}升级了,现在你的级别是{}。".format(self.name, now_level))
self.__init__(self.name, self.experience)
def die(self):
'''
死亡方法
主要功能
经验值减100,并调用实例构造方法,根据新的经验值重新计算其它各属性值。
'''
self.experience = self.experience - 100
self.__init__(self.name, self.experience)
print("{}掉了一级,现在的级别是{}".format(self.name, self.level))
def hunt(self):
pass
def match_fight(self):
pass
class Magician(Hero):
'''
法师类
'''
def __init__(self, name,experience):
'''
调用父类构造方法后,重写magic_attack,
法师类魔法攻击基础值为80,每级别上涨60。
'''
super().__init__(name, experience)
self.magic_attack = 80 + (self.level*60)
class Shooter(Hero):
'''
射手类
'''
def __init__(self, name, experience):
'''
调用父类构造方法后,重写physical_attack,
射手类物理攻击基础值为200,每级别上涨50。
'''
super().__init__(name, experience)
self.physical_attack = 200 + (self.level*50)
class Tank(Hero):
'''
坦克类
'''
def __init__(self, name,experience):
'''
调用父类构造方法后,重写health、physical_armor和magic_armor。
'''
super().__init__(name, experience)
self.health = 2000 + (self.level*200)
self.physical_armor = 80 + (self.level*20)
self.magic_armor = 80 + (self.level*30)
# 构造一个射手实例xiaoxiang,name为Draven,经验是0
xiaoxiang = Shooter('Draven',0)
# 构造一个法师实例daxiang,name为Ryze,经验是100
daxiang = Magician('Ryze',100)
# 打印出daxiang的姓名和血量
print('daxiang的姓名是{}血量是{}'.format(daxiang.name,daxiang.health))
# 指挥xiaoxiang去攻击daxiang
xiaoxiang.attack(daxiang)
# 打印出daxiang现在的姓名和血量
print('daxiang的姓名是{}血量是{}'.format(daxiang.name,daxiang.health))
# 打印出daxiang现在的等级
print('daxiang现在的等级是{}'.format(daxiang.level))
# 为daxiang增加200的经验
daxiang.level_up(200)
# 打印出daxiang姓名和现在的等级
print('daxiang现在的等级是{}'.format(daxiang.level))
# 让daxiang死亡一次
daxiang.die()攻击方法:如果攻击力小于敌人的护甲,则相应的伤害是0,否则伤害=攻击力-敌人护甲。
升级方法:需要传入一个value参数,代表经验的增长值,然后把value加到实例变量self.experience上。接着根据当前的经验值计算等级,如果等级增长了,打印出消息进行提示,并且调用构造方法,根据新的经验值,计算血量、攻击力等其它属性。
死亡方法:经验值减少100,然后调用实例的构造方法,根据新的经验值重新计算实例的级别、血量、攻击力等其它属性。
if的三元表达式

总结
object类:Python自定义的祖先类,所有类默认继承object类。
继承:子类从父类继承属性和方法。
重写:实现多态性的重要手段,指的是子类重新定义变量和方法。 
练习:指挥daxiang去狩猎,猎物为xiaoxiang
class Hero():
def __init__(self, name, experience):
'''
实例构造方法
传入参数
name:名称
experience:经验值
主要功能
属性初始化操作。根据输入的经验值,计算与该经验值对应的
级别、血量、物理攻击、物理防御、魔法攻击、魔法防御值。
'''
self.name = name
self.experience = experience
self.level = self.experience // 100
self.health = 1000 + (self.level*100)
self.physical_attack = 150 + (self.level*20)
self.physical_armor = 50 + (self.level*10)
self.magic_armor = 50 + (self.level*20)
self.magic_attack = 0
def attack(self, enemy):
'''
攻击方法
传入参数
enemy:被攻击的实例
主要功能
分别计算物理伤害及魔法伤害,并将enemy的血量降低相应的伤害值。
'''
# 物理伤害等于当前实例物理攻击能力减敌人物理防御能力
# 如果攻击能力低于防御能力,物理伤害为0
physical_hurt = 0 if self.physical_attack < enemy.physical_armor else (self.physical_attack - enemy.physical_armor)
# 魔法伤害等于当前实例魔法攻击能力减敌人魔法防御能力
# 如果攻击能力低于防御能力,魔法伤害为0
magic_hurt = 0 if self.magic_attack < enemy.magic_armor else (self.magic_attack - enemy.magic_armor)
# 根据伤害能力,设置enemy的血量为原血量减掉伤害值
enemy.health = enemy.health - physical_hurt - magic_hurt
print("{}攻击了{},一共造成{}点伤害。".format(self.name, enemy.name, (physical_hurt + magic_hurt)))
def level_up(self, value):
'''
升级方法
传入参数
value:增加的经验值
主要功能
将当前实例的经验值增加value,并根据新的经验值计算对应的级别。
如果此次经验值增加导致了升级,调用实例构造方法重新计算新的级别、血量及各攻击和防御能力。
'''
# 增加经验值
self.experience = self.experience + value
# 根据新的经验值计算级别
now_level = self.experience // 100
# 如果新计算的级别比原来的级别高,打印恭喜信息,并调用实例构造方法重新计算各属性
if now_level > self.level:
print("恭喜{}升级了,现在你的级别是{}。".format(self.name, now_level))
self.__init__(self.name, self.experience)
def die(self):
'''
死亡方法
主要功能
经验值减100,并调用实例构造方法,根据新的经验值重新计算其它各属性值。
'''
self.experience = self.experience - 100
self.__init__(self.name, self.experience)
print("{}掉了一级,现在的级别是{}".format(self.name, self.level))
def hunt(self, monster):
huihe = 1
while True:
print('第{}回合'.format(huihe))
self.attack(monster)
if monster.health<=0:
self.level_up(80)
break
monster.attack(self)
if self.health<=0:
self.die()
break
huihe+=1
def match_fight(self):
pass
class Magician(Hero):
'''
法师类
'''
def __init__(self, name,experience):
'''
调用父类构造方法后,重写magic_attack,
法师类魔法攻击基础值为80,每级别上涨60。
'''
super().__init__(name, experience)
self.magic_attack = 80 + (self.level*60)
class Shooter(Hero):
'''
射手类
'''
def __init__(self, name, experience):
'''
调用父类构造方法后,重写physical_attack,
射手类物理攻击基础值为200,每级别上涨50。
'''
super().__init__(name, experience)
self.physical_attack = 200 + (self.level*50)
class Tank(Hero):
'''
坦克类
'''
def __init__(self, name,experience):
'''
调用父类构造方法后,重写health、physical_armor和magic_armor。
'''
super().__init__(name, experience)
self.health = 2000 + (self.level*200)
self.physical_armor = 80 + (self.level*20)
self.magic_armor = 80 + (self.level*30)
xiaoxiang = Shooter("Draven", 1000)
daxiang = Magician("Ryze", 100)
# 指挥daxiang去狩猎,猎物为xiaoxiang
daxiang.hunt(xiaoxiang)