天天看点

python面向对象---03-继承、多继承、super

python面向对象—03-继承、多继承、super

阶段一:继承

情景模式:假设你正在参与一个魔幻类角色游戏的开发,公司需要你为这个游戏设计两个角色的类:

  1. 剑士
    • 具有如下属性:
      • 角色名
      • 角色等级
      • 生命值
      • 攻击力
    • 具有如下行为:
      • 物理攻击
  2. 法师
    • 具有如下属性:
      • 角色名
      • 角色等级
      • 生命值
      • 攻击力
    • 具有如下行为:
      • 物理攻击

代码实现:

英勇的剑士:

class SwordsMan:
    def __init__(self, name, level, blood, attack_power):
        '''
        :param name:角色姓名
        :param level:角色等级
        :param blood:角色血量
        '''
        self.name = name
        self.level = level
        self.blood = blood
        self.power = attack_power

    def fight(self):   #角色攻击行为
        print('物理攻击')
    def __str__(self):
        return "{clc}({name},{level},{blood})".format(clc = self.__class__.__name__,
                                                      name = self.name,
                                                      level = self.level,
                                                      blood = self.blood)
           

智慧的法师:

class Magician:
    def __init__(self, name, level, blood, magic_power):
        '''
        :param name:角色姓名
        :param level:角色等级
        :param blood:角色血量
        '''
        self.name = name
        self.level = level
        self.blood = blood
        self.power = magic_power
    def fight(self):   #角色攻击行为
        print('魔法攻击')
    def __str__(self):
        return "{clc}({name},{level},{blood})".format(clc = self.__class__.__name__,
                                                      name = self.name,
                                                      level = self.level,
                                                      blood = self.blood)
           

继承 问题引入

问题一: 两个中有大量重复的代码,是否能够只写一次 ?

  • 抽象出一个更抽象的类,放公共代码

问题二: 继承的意义是什么 ?

  • 重用代码,方便代码的管理和修改

问题三: 继承是复制变量空间嘛 ?

  • 继承不是变量空间复制

分类关系图

python面向对象---03-继承、多继承、super

对以上连个角色进行进一步抽象,定义一个更加抽象的类— 角色类

代码如下:

class Rloe:
    def __init__(self,name,level,blood):
        '''
        :param name:角色姓名
        :param level:角色等级
        :param blood:角色血量
        '''
        self.name = name
        self.level =level
        self.blood = blood

    def __str__(self):
        return "{clc}({name},{level},{blood})".format(clc = self.__class__.__name__,
                                                      name = self.name,
                                                      level = self.level,
                                                      blood = self.blood)

    def fight(self):  # 角色攻击行为
        raise NotImplementedError('必须在子类中实现该行为')   
           

继承关系图

python面向对象---03-继承、多继承、super

再从角色类中派生具体的类

注意:(派生与继承是一个意思的两个说法)

派生出的剑士:

class SwordsMan(Rloe):     #继承自Role
    def __init__(self,name,level,blood,attack_power):
        '''
        :param name:角色姓名
        :param level:角色等级
        :param blood:角色血量
        '''
        Rloe.__init__(self,name,level,blood)
        self.attack_power = attack_power
    def fight(self):   #角色攻击行为
        print('物理攻击')
           

派生出的法师:

class Magician:        #继承自Role
    def __init__(self,name,level,blood,magic_power):
        '''
        :param name:角色姓名
        :param level:角色等级
        :param blood:角色血量
        '''
        Rloe.__init__(self, name, level, blood)
        self.attack_power = attack_power
    def fight(self):   #角色攻击行为
        print('魔法攻击')
    def cure(self):  # 角色技能
        print('治疗')
           

继承搜索

搜索原则:(访问类的属性或方法)

  • 如果找不到转到其父类中查找
  • 如果再找不到转到其父类的父类中查找

实例:

class BaseClass:
    attritube = 
    def method(self):
        pass
class DeriverClass:    #简单继承,没有任何的封装,重写
    pass
print(DeriverClass.__dict__)  #DeriverClass中没有attritube与method
print(BaseClass.__dict__)     #BaseClass中有
           

重用父类的 _ init_

左边的self 是 剑士(子类)的实例 右边的self是也是剑士的实例

python面向对象---03-继承、多继承、super

顶级基类 object

class ClassName:
    pass
class ClassN(object):
    pass
print(ClassName.__bases__)
print(ClassN.__bases__)
           

思考:为什么返回的是一个元祖 ?

  • 有可能继承多个类(及多继承),以元组显示。

阶段二:多重继承

多重继承 问题引入

问题一: 一个类只能有一个基类嘛 ?

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

问题三: 有没有一种更加优雅的方式调用父类的方法 ?

继承关系图:

python面向对象---03-继承、多继承、super

代码实现如下:

class D:
    pass
class E:
    pass
class C:
    pass
class B(D,E):
    pass
class A(B,C):
    pass

print(A.mro())
           

结果输出:

[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.C'>, <class 'object'>]

进程已结束,退出代码0
           

MRO-C3 搜索分析

S[D] = <D O>
S[E] = <E O>
S[C] = <C O>

S[B] = B + merge(S[D], S[E], <D E>)
        = B + merge(<D O>, <E O>, <D E>)
        = <B D> + merge(O, <E O>, E)
        = <B D E O>

S[A] = A + merge(S[B], S[C], <B C>)
        = A + merge(<B D E O>, <C O>, <B C>)
        = <A B> + merge(<D E O>, <C O>, C)
        = <A B D> + merge(<E O>, <C O>, C)
        = <A B D E> + merge(O, <C O>, C)
        = <A B D E C O>
           

由于冲突导致的不能继承

python面向对象---03-继承、多继承、super

代码实现如下:

class A:
    pass
class B:
    pass
class C(A,B):
    pass
class D(B,A):
    pass
class E(C,D):
    pass

print(E.mro())
           

结果输出:

Traceback (most recent call last):
  File "G:/xxx/xxx/xxx/xxx/TTT.py", line , in <module>
    class E(C,D):
TypeError: Cannot create a consistent method resolution
order (MRO) for bases A, B
           

MRO-C3 搜索分析

S[A] = <A O>
S[B] = <B O>

S[C] = C + merge(S[A], S[B], <A B>)
        = C + merge(<A O>, <B O>, <A B>)
        = <C A> + merge(O, <B O>, <B>)
        = <C A B O>
S[D] = <D B A O>

S[E] = E + merge(S[C], S[D], <C D>)
        = E + merge(<C A B O>, <D B A O>, <CD>)
        = <E C> + merge(<A B O>, <D B A O>, <D>)
        = <E C D> + merge(<A B O>, <B A O>)    # 冲突
           

鸭子类型

实例:

def draw_fight(role):
  print('role',end='')
  role.fight()    #其实并不关心,role是不是一个实例
class SwordsMan:
    def __init__(self, name, level, blood, attack_power):
        '''
        :param name:角色姓名
        :param level:角色等级
        :param blood:角色血量
        '''
        self.name = name
        self.level = level
        self.blood = blood
        self.power = attack_power

    def fight(self):   #角色攻击行为
        print('物理攻击')
    def __str__(self):
        return "{clc}({name},{level},{blood})".format(clc = self.__class__.__name__,
                                                      name = self.name,
                                                      level = self.level,
                                                      blood = self.blood)
class Magician:
    def __init__(self, name, level, blood, magic_power):
        '''
        :param name:角色姓名
        :param level:角色等级
        :param blood:角色血量
        '''
        self.name = name
        self.level = level
        self.blood = blood
        self.power = magic_power
    def fight(self):   #角色攻击行为
        print('魔法攻击')
    def __str__(self):
        return "{clc}({name},{level},{blood})".format(clc = self.__class__.__name__,
                                                      name = self.name,
                                                      level = self.level,
                                                      blood = self.blood)

s = SwordsMan('lili',,,)
m = Magician('haha',,,)
draw_fight(s)  #打印出:role物理攻击
draw_fight(m)  #打印出:role魔法攻击
           

如果走起路来像鸭子,或者叫起来像鸭子,那就是鸭子!

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

python面向对象---03-继承、多继承、super

原则:

  • 最好,多继承就一层,且是最后一层
  • 注意:一般,“Mix-in类”是继承的终点 !

阶段三:super 内置函数

如何更加优雅的调用父类中方法?

代码实现如下:

剑士super方法改进:

class SwordsMan(Rloe):     #继承自Role
    def __init__(self,name,level,blood,attack_power):
        '''
        :param name:角色姓名
        :param level:角色等级
        :param blood:角色血量
        '''
        super().__init__(name,level,blood)
        self.attack_power = attack_power
    def fight(self):   #角色攻击行为
        print('物理攻击')
           

法师剑士super方法改进:

class Magician:        #继承自Role
    def __init__(self,name,level,blood,magic_power):
        '''
        :param name:角色姓名
        :param level:角色等级
        :param blood:角色血量
        '''
        super().__init__(name, level, blood)
        self.attack_power = attack_power
    def fight(self):   #角色攻击行为
        print('魔法攻击')
    def cure(self):  # 角色技能
        print('治疗')
           

super不需要再传self、super是通过mro查找的

练习:

eg:

假设你正在参与潭州教育公司的软件学员管理系统开发,需要你为系统设计学员类:潭州教育软件类别:

  1. C/C++
  2. Web前端
  3. Python

请设计一个基类表示学员,然后使用继承来实现各科目的软件学员。

代码实现如下:

class Student:
    def __init__(self,name,age,sex):
        '''
        :param name:学员姓名
        :param age:学员年龄
        :param sex:学员性别
        '''
        self.name = name
        self.age =age
        self.sex = sex
    def __str__(self):
        return "{clc}({name},{age},{sex})".format(clc = self.__class__.__name__,
                                                      name = self.name,
                                                      age = self.age,
                                                      sex = self.sex)

    def learn(self):  # 学员学习课程
        raise NotImplementedError('必须在子类中实现该方法')

class C(Student):     #继承自Student
    def __init__(self,name,age,sex,lesson):
        '''
         :param name:学员姓名
        :param age:学员年龄
        :param sex:学员性别
        '''
        super().__init__(name,age,sex)
        self.lesson = lesson
    def learn(self):   #学习课程
        print('学习C/C++课程')

class Web(Student):         #继承自Student
    def __init__(self,name,age,sex,lesson):
        '''
         :param name:学员姓名
        :param age:学员年龄
        :param sex:学员性别
        '''
        super().__init__(name,age,sex)
        self.lesson = lesson
    def learn(self):   #学习课程
        print('学习Web前端课程')

class Python(Student):         #继承自Student
    def __init__(self,name,age,sex,lesson):
        '''
         :param name:学员姓名
        :param age:学员年龄
        :param sex:学员性别
        '''
        super().__init__(name,age,sex)
        self.lesson = lesson
    def learn(self):   #学习课程
        print('学习Python课程')
c= C('lili',,'M','c/c++')
w= Web('haha',,'F','Web前端')   
p= Python('dada',,'M','Python')
print(c)
c.learn()
print(w)
w.learn()
print(p)
p.learn()
           

输出结果:

C(lili,,M)
学习C/C++课程
Web(haha,,F)
学习Web前端课程
Python(dada,,M)
学习Python课程
>>>