python进阶03 继承

python进阶03 继承

一、继承

  课堂练习:假设你正在参与一个魔幻类角色游戏的开发,公司需要腻味这个游戏设计两个角色的类:

  a、剑士   

    属性:1、角色名;2、角色等级;3、生命值;4、攻击力

    行为:物理攻击

  b、法师

    属性:1、角色名;2、角色等级;3、生命值;4、法术强度

    行为:1、法术攻击;2、治疗

#首先定义一个剑士类
class SwordsMan:#定义一个剑士类
    def __init__(self,name,lever,blood): #初始化剑士的名字,等级,血量
        self.name=name
        self.lever=level
        self.blood=blood
   
    def fight(self): #行为函数 攻击方式:物理攻击
        print('物理输出')

    def __repr__(self): #str没有的时候会找repr
        return '{cls}{name}{level}{blood}'.format(cls=__class__.__name__,name=self.name,level=self.level,blood=self.blood) #cls=__class__.__name__表示不管当前是哪个类,用这种方法就可以输出类名(好处在于不用指定类名,让系统自己算出自己的类名)
#然后定义一个法师类
class Magician:#定义一个法师类
    def __init__(self,name,lever,blood): #初始化剑士的名字,等级,血量
        self.name=name
        self.lever=level
        self.blood=blood
   
    def fight(self): #行为函数 攻击方式:物理攻击
        print('法术攻击')

    def cure(self):#行为函数 治疗
        print('治疗')

    def __repr__(self): #str没有的时候会找repr
        return '{cls}{name}{level}{blood}'.format(cls=__class__.__name__,name=self.name,level=self.level,blood=self.blood)    

  两个类中有大量重复的代码,是否可以只写一次(两个类之间有交集)

  剑士和法师都是角色,那么我们可以定义一个剑士和法师都隶属的角色类

class Role:#
    def __init__(self,name,lever,blood): 
        self.name=name
        self.lever=level
        self.blood=blood
   
    def fight(self):
        raise NotImplementedError('攻击方式没有实现')#raise:自己丢出异常(认为异常/自己丢出异常);NotImplementedError:表示必须要在子类中去实现,Not表示没有 implemented表示实现

    def __repr__(self): 
        return '{cls}{name}{level}{blood}'.format(cls=__class__.__name__,name=self.name,level=self.level,blood=self.blood)    

  然后就是继承,就是从角色类中派生(也就是继承)出各自的类

class SwordsMan(Role): #如果什么都不写,就是跟父类Role一模一样
    pass 

#剑士类

class SwordsMan(Role):
    def init(self,name,level,blood,attack_power):
        Role.__init__(self,name,level,blood) #这样手动调一次父类中已经定义的东西,公共的部分父类帮你初始化,子类的部分自己定义
        self.attack_power=attack_power
    
    def fight(self):#父类里面有的,子类里面再写一次,叫做重写
        print('物理攻击')

#同理 法师
class Mgician(Role):
    def init(self,name,level,blood,attack_power):
        Role.__init__(self,name,level,blood) 
        self.magic_power=magic_power
    
    def fight(self):
        print('魔法攻击')

    def cure(self):
        print('治疗')

  继承搜索

#访问类的属性和方法-->类 (如果找不到,转到其父类中查找) -->直接基类(如果再找不到,转到其父类的父类中去查找)-->间接基类

#所以继承不是变量空间的复制

#属性查找
class Role:
    pass

class MyRole(Role):
    pass

print(MyRole.__dict__) #查找MyRole

#在子类中查找到了init,父类中的init就会被屏蔽

  关于重用父类的init

class SwordsMan(Role):

    def init(self,name,level,blood,attack_power):#子类中查找的self是剑士的实例
        Role.__init__(self,name,level,blood) #在父类中查找出的self也是剑士的实例
        self.attack_power=attack_power


#相当于
    def __init__(self,name,level,blood,attack_power):
        self.name=name
        self.level=level
        self.blood=blood
        self.attack_power=attack_power

  顶级基类object:所有类最终的父类,类似于树的跟

#假如我拿到了别人写的库或者框架
#人家肯定用到了面向对象,肯定会有继承
#我正在用这个类,我想了解他的继承关系,想知道它继承于什么类

print(Magician.__bases__) #输出(Role)查找Magician类继承于什么类

  继承的意义:重用代码,方便代码的管理和修改

二、多重继承

  如果有多个基类,有同名属性和方法,应该如何选择

class D:
    pass

class E:
    pass

class C:
    pass 

class B(D,E): #B继承于D,E
    pass

class A(B,C):
    pass

#到底是广度查找(A B C A E)还是(A B D E C)
#不是以上两种方法,而是MRO-C3算法

print(A.mro()) #mro方法,是在类里面的,它会自己计算出,搜索顺序

  C3算法会由于冲突导致不能继承

class A:
    pass

class B:
    pass

class C(A,B):
    pass

class D(B,A):
    pass

class E(C,D): 
    pass

#会报错,这个顺序是违反了C3规则
#对于C而言,A比B优先;对于D而言,B比A优先,而E继承C和D就爆炸了

  鸭子类型:如果走起来或叫起来像鸭子,那么你就是鸭子

class SwordsMan(Role):
    def init(self,name,level,blood,attack_power):
        Role.__init__(self,name,level,blood) 
        self.attack_power=attack_power
    
    def fight(self):
        print('物理攻击')

#展示出攻击的效果(这件事不属于任何一个角色)
#写一个函数
def draw_fight(role): #鸭子类型体现出来的是,一个函数关心的不是类型,而是行为
    print('role',end='')
    role.fight() #要求你传入一个Role,传入剑士的实例可以吗?可以。因为剑士也是角色,我不管你是什么类,只要你有fight方法,我就认为你是个角色

s=SwordsMan('A',18,3000,8888)
draw_fight(a) #输出role 物理攻击


class Girlfriend:

    def __init__(self,name):
        self.name=name

    def fight(self):
        print('拔电源攻击')

g=Girlfriend('xiaopo')
draw_fight()#输出role 拔电源攻击 


综上鸭子类型,只要你有这个行为,你就是鸭子

  基于多继承的Mix-in设计模式

 

#单继承就是分类思想,爸爸就只有一个,往下无限繁衍
#多继承就是拼积木(Mix-in)思想
#注意:一般“Mix-in”是继承的终点,只继承一次,通俗的讲:就是胳膊有人这个爸爸,脑袋有人这个爸爸,腿有人这个爸爸,这三个最好不要有其他爸爸,人上面也别在生出个爸爸

三、super函数

 更加优雅地调用父类中的方法

 

#在角色和剑士中间加了两个分类:英雄和NPC,怎么办
class Hero:
    pass

class NPC:
    pass

class SwordsMan(Role):
    def init(self,name,level,blood,attack_power):
        Role.__init__(self,name,level,blood) #如果我在做游戏,Role只是角色,角色又可以分为英雄和NPC。这便需要将Role变为Hero,也就是在调用父类方法的时候要变为Hero了,上面类中的Role也要换,这样很不优雅
        self.attack_power=attack_power

改变为下面这个即可:
class SwordsMan(Role):
    def init(self,name,level,blood,attack_power):
        super().__init__(name,level,blood) #将前面的Role变为super,后面的self去掉,系统会自动查找父类
        self.attack_power=attack_power

 

posted on 2018-02-11 15:05  许铖铖  阅读(179)  评论(0编辑  收藏  举报