zoukankan      html  css  js  c++  java
  • python 类的三大特性--继承

    继承                                                                                                                

    继承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题,

    继承是一种创建新类的方式,在python中新建的类可以继承一个或多个父类,父类可称为基类或者超类,新建的类称为派生类或子类。

    python中类的继承分为:单继承和多继承

    class Biology:                # 定义一个父类
        pass
    
    
    class Animal:                 # 定义一个父类
        pass
    
    
    class Person(Biology):        # 单继承,基类是Biology, 派生类是person
        pass
    
    
    class Dog(Biology, Animal):   # 多继承,用逗号隔开多个基类
        pass

    查看继承:

    # 可通过类名.__bases__查看所有继承的父类,类名.__base__只查看从左到右继承的第一个父类
    print(Dog.__base__)
    # <class '__main__.Biology'>
    print(Dog.__bases__)
    # (<class '__main__.Biology'>, <class '__main__.Animal'>)

    经典类和新式类:

    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 = defensive
    
        def attack(self, enemy):  # 类的技能,英雄具有攻击技能
            enemy.life_value -= self.aggressivity
          
            
    class Garen(Hero):                  # Garen类继承Hero类
        pass
    
    
    class Riven(Hero):                 # Riven类继承Hero类
        pass
    
    
    garen1 = 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线性化算法来实现的。

    class A(object):
        def test(self):
            print("from a")
    class B(A):
        pass
        # def test(self):
        #     print("from b")
    
    class C(A):
        pass
        # def test(self):
        #     print("from c")
    class D(B):
        pass
        # def test(self):
        #     print("from d")
    class E(C):
        pass
        # def test(self):
        #     print("from e")
    class F(A):
        pass
        # def test(self):
        #     print("from f")
    class H(D,E,F):
        pass
    h1 = H()
    h1.test()            # from a
    print(H.__mro__)   #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
    # (<class '__main__.H'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.A'>, <class 'object'>)

    子类里调用父类的方法

    在子类派生出的新方法中,往往需要重用父类的方法,我们有两种方式实现

    一、指名道姓,即父类名.父类方法()

    二、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 = defensive
        
        def attack(self, enemy):  # 类的技能,英雄具有攻击技能
            enemy.life_value -= self.aggressivity
    
    
    class 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 = sex
            
        def attack(self, enemy):  # 子类可以重新定义攻击技能,不会改变父类的攻击方法
            enemy.life_value -= (self.aggressivity - enemy.defensive)
        
        def life_reply(self):  # 子类可以新加一个生命恢复技能
            self.life_value += 20
    
    
    class Riven(Hero):  # Riven类继承Hero类
        pass
    
    garen1 = 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()继续往后找
    class A:
        def test(self):
            super().test()
    class B:
        def test(self):
            print('from B')
    class C(A,B):
        pass
    
    c=C()
    c.test() #打印结果:from B
    
    
    print(C.mro())
    #[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

    组合                                                                                                                                        

    组合指的是类与类之间的关系,是一种什么“有”什么的关系,在一个类中以另一个类的对象作为数据属性,称为类的组合

    class Arms:  # 定义一个武器类
        def __init__(self, aggressivity):  # 定义武器攻击力属性
            self.aggressivity = aggressivity
    
    
    class 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.aggressivity
            if self.arm:    # 判断是否装备了武器
                for i in self.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)

    总结:

    当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好

  • 相关阅读:
    struts2标签处理下拉列表
    JS中parseInt使用问题解析
    使用jquery异步无刷新删除
    html中table标签的td标签居中左(右)对齐
    struts2拦截器来防止sql注入
    在S2SH中调用返回参数的存储过程
    使用jquery的getJSON从服务器端获得数据
    【vue】vuecli中 对于public文件夹的处理
    oracle10新建表时大小定问题
    会议记录
  • 原文地址:https://www.cnblogs.com/zt0903/p/10832971.html
Copyright © 2011-2022 走看看