zoukankan      html  css  js  c++  java
  • Python之继承

    1、什么是继承?

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

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

    class ParentClass1: #定义父类
        pass
    
    class ParentClass2: #定义父类
        pass
    
    class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass
        pass
    
    class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
        pass
    
    print(Son1.__bases__)  # 查看所有继承的父类
    print(Son2.__bases__)
    ===============
    (<class '__main__.Father1'>,)
    (<class '__main__.Father1'>, <class '__main__.Father2'>)
    View Code

    2、继承与抽象

    抽象分成两个层次:

    1.将奥巴马和梅西这俩对象比较像的部分抽取成类;

    2.将人,猪,狗这三个类比较像的部分抽取成父类。

    抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)

    clip_image001

    继承:

    是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。

    抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类

    clip_image002

    class animal():   # 定义父类
        country  =  'china'     # 这个叫类的变量
        def __init__(self,name,age):
            self.name=name   # 这些又叫数据属性
            self.age=age
    
        def walk(self):         # 类的函数,方法,动态属性
            print('%s is walking'%self.name)
    
        def say(self):
            pass
    
    class people(animal):  # 子类继承父类
        pass
    
    class pig(animal):    # 子类继承父类
        pass
    
    class dog(animal):  # 子类继承父类
        pass
    
    aobama=people('aobama',60)   # 实例化一个对象
    print(aobama.name)
    aobama.walk()
    ===================
    aobama
    aobama is walking
    View Code

    3、派生

    1.在父类的基础上产生子类,产生的子类就叫做派生类

    2.父类里没有的方法,在子类中有了,这样的方法就叫做派生方法。

    3.父类里有,子类也有的方法,就叫做方法的重写(就是把父类里的方法重写了)

    class Hero:
        def __init__(self, nickname,
                     aggressivity,
                     life_value):
            self.nickname = nickname
            self.aggressivity = aggressivity
            self.life_value = life_value
    
        def attack(self, enemy):
            enemy.life_value -= self.aggressivity
    
    class Garen(Hero):   # 子类继承  hero 父类
        camp='Demacia'   # 子类衍生出的变量
        def attack(self, enemy):   # 跟父类的 attack 重名,对象调用的时候以子类的为准
            pass
        def fire(self):    # 父类没有 fire,这里 fire 属于派生出来的东西
            print('%s is firing' %self.nickname)
    class Riven(Hero):
        camp='Noxus'
    
    g1=Garen('garen',18,200)
    r1=Riven('rivren',18,200)
    # print(g1.camp)
    # print(r1.camp)
    # g1.fire()
    g1.attack(g1)
    例1
    class Hero:
        def __init__(self, nickname,aggressivity,life_value):
            self.nickname = nickname
            self.aggressivity = aggressivity
            self.life_value = life_value
        def attack(self, enemy):
            print('Hero attack')
    
    class Garen(Hero):
        camp = 'Demacia'
    
        def attack(self, enemy): #self=g1,enemy=r1
            # self.attack(enemy) #g1.attack(r1),这里相当于无限递归
            Hero.attack(self,enemy)  # 引用 父类的 attack,对象会去跑 父类的 attack
            print('from garen attack')  # 再回来这里
    
        def fire(self):
            print('%s is firing' % self.nickname)
    
    class Riven(Hero):
        camp = 'Noxus'
    
    
    g1 = Garen('garen', 18, 200)
    r1 = Riven('rivren', 18, 200)
    g1.attack(r1)
    # print(g1.camp)
    # print(r1.camp)
    # g1.fire()
    例2

    4、组合与重用性

    重用性:

    方式1:不通过继承的方式重用属性,指名道姓的使用哪个类的属性

    class Hero:
        def __init__(self,nickname,gongji,life):
            self.nickname=nickname
            self.gongji=gongji
            self.life=life
    
        def attack(self,obj):
            print('from Hero attack')
    
    class Garen:
        def __init__(self,nickname,gongji,life,script):
            Hero.__init__(self,nickname,gongji,life)   # 这里引用Hero类的 init,不用再自己从新定义一遍 init
            self.script=script   # 父类 init 没有 script,这里是新加进来的属性
    
        def attack(self,obj):  # 在这里自己定义新的 attack,不再使用父类的 attack
            print('from Garen attack')
    
        def fire(self):  # 在这里定义新的功能
            print('from Garen fire')
    
    g1=Garen('garen',18,200,'人在塔在')
    print(g1.script)
    人在塔在
    View Code

    提示:用已经有的类建立一个新的类,这样就重用了已经有的软件中的一部分甚至大部分,大大省了编程工作量,这就是常说的软件重用,不仅可以重用自己的类,也可以继承别人的,比如标准库,来定制新的数据类型,这样就是大大缩短了软件开发周期,对大型软件开发来说,意义重大.

    注意:像g1.life之类的属性引用,会先从实例中找life,然后去类中找,然后再去父类中找...直到最顶级的父类。

    方式2:通过继承

    class Hero():
        def __init__(self, nickname, gongji, life):
            self.nickname = nickname
            self.gongji = gongji
            self.life = life
    
        def attack(self, obj):
            print('from Hero attack')
            obj.life -= self.gongji
    
    
    class Garen(Hero):   # 使用 super方式需要继承
        camp = 'Demacia'
    
        def __init__(self, nickname, gongji, life):
            super().__init__(nickname, gongji, life)
    
        def attack(self, obj):  # 在这里自己定义新的 attack,不再使用父类的 attack
            super(Garen, self).attack(obj)  # PY3中super可以不给参数,PY2中第一个参数必须是自己的类,self,可以使用父类的方法,方法需要给参数就给参数
    
        def fire(self):  # 在这里定义新的功能
            print('from Garen fire')
    
    
    g1 = Garen('garen1', 18, 200)
    g2 = Garen('garen2', 20, 100)
    print(g2.life)
    g1.attack(g2)
    print(g2.life)
    
    100
    from Hero attack
    82
    例1
    class A:
        def f1(self):
            print('from A')
            super().f1()    
            # 这种不需要继承也可以使用到 super,为什么,要看 C的 MRO表
    
    
    class B:
        def f1(self):
            print('from B')
    
    class C(A,B):
        pass
    
    
    print(C.mro())
    #[<class '__main__.C'>,
    # <class '__main__.A'>,
    # <class '__main__.B'>, #  B在A的后面,当A指定 super().f1 会找到 B的 f1
    # <class 'object'>]
    
    
    c=C()
    c.f1()
    例2

    组合:

    软件重用的重要方式除了继承之外还有另外一种方式,即:组合

    组合:一个对象的数据属性是另一个对象,称为组合

    class Equip: #武器装备类
        def fire(self):
            print('release Fire skill')
    
    class Riven: #英雄Riven的类,一个英雄需要有装备,因而需要组合Equip类
        camp='Noxus'
        def __init__(self,nickname):
            self.nickname=nickname
            self.equip=Equip() #用Equip类产生一个装备,赋值给实例的equip属性
    
    r1=Riven('锐雯雯')
    r1.equip.fire() #可以使用组合的类产生的对象所持有的方法
    
    release Fire skill
    View Code

    组合的方式:

    组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同

    1.继承的方式

    通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。

    当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人

    2.组合的方式

    用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...

    class People:
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
    class Course:
        def __init__(self,name,period,price):
            self.name=name
            self.period=period
            self.price=price
        def tell_info(self):
            print('<%s %s %s>' %(self.name,self.period,self.price))
    
    class Teacher(People):
        def __init__(self,name,age,sex,job_title):
            People.__init__(self,name,age,sex)
            self.job_title=job_title
            self.course=[]
            self.students=[]
    
    
    class Student(People):
        def __init__(self,name,age,sex):
            People.__init__(self,name,age,sex)
            self.course=[]
    
    
    egon=Teacher('egon',18,'male','沙河霸道金牌讲师')
    s1=Student('牛榴弹',18,'female')
    
    python=Course('python','3mons',3000.0)
    linux=Course('python','3mons',3000.0)
    
    #为老师egon和学生s1添加课程
    egon.course.append(python)
    egon.course.append(linux)
    s1.course.append(python)
    
    #为老师egon添加学生s1
    egon.students.append(s1)
    
    
    #使用
    for obj in egon.course:
        obj.tell_info()
    View Code

    5、接口与归一化设计

    a、为何要用接口?

    接口提取了一群类共同的函数,可以把接口当做一个函数的集合。

    然后让子类去实现接口中的函数。

    这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。

    归一化的好处在于:

    归一化让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。

    class Interface:#定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。
        def read(self): #定接口函数read
            pass
    
        def write(self): #定义接口函数write
            pass
    
    
    class Txt(Interface): #文本,具体实现read和write
        def read(self):
            print('文本数据的读取方法')
    
        def write(self):
            print('文本数据的读取方法')
    
    class Sata(Interface): #磁盘,具体实现read和write
        def read(self):
            print('硬盘数据的读取方法')
    
        def write(self):
            print('硬盘数据的读取方法')
    
    class Process(Interface):
        def read(self):
            print('进程数据的读取方法')
    
        def write(self):
            print('进程数据的读取方法')
    View Code

    上面的代码只是看起来像接口,其实并没有起到接口的作用,子类完全可以不用去实现接口,这就用到了抽象类

    6、抽象类

    子类必须继承抽象类的方法,不然报错

    什么是抽象类?

    与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

    为什么要有抽象类?

    如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。

     比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。

    从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

      从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。

    抽象类与接口

    抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

    抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计

    import abc
    #抽象类:本质还是类,与普通类额外的特点的是:加了装饰器的函数,子类必须实现他们
    class Animal(metaclass=abc.ABCMeta):   # 抽象类是用来被子类继承的,不是用来实例化的
        tag='123123123123123'
        @abc.abstractmethod   # 如果子类没有我这个函数,主动抛出异常
        def run(self):
            pass
        @abc.abstractmethod
        def speak(self):
            pass
    
    
    
    class People(Animal):
        def run(self):   # 子类必须有抽象类里的装饰器下面的函数
            pass
    
        def speak(self):
            pass
    
    
    peo1=People()   # 实例化出来一个人
    print(peo1.tag)
    例1
    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    #一切皆文件
    import abc #利用abc模块实现抽象类
    
    class All_file(metaclass=abc.ABCMeta):
        all_type='file'
        @abc.abstractmethod #定义抽象方法,无需实现功能
        def read(self):
            '子类必须定义读功能'
            pass
    
        @abc.abstractmethod #定义抽象方法,无需实现功能
        def write(self):
            '子类必须定义写功能'
            pass
    
    # class Txt(All_file):
    #     pass
    #
    # t1=Txt() #报错,子类没有定义抽象方法
    
    class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print('文本数据的读取方法')
    
        def write(self):
            print('文本数据的读取方法')
    
    class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print('硬盘数据的读取方法')
    
        def write(self):
            print('硬盘数据的读取方法')
    
    class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print('进程数据的读取方法')
    
        def write(self):
            print('进程数据的读取方法')
    
    wenbenwenjian=Txt()
    
    yingpanwenjian=Sata()
    
    jinchengwenjian=Process()
    
    #这样大家都是被归一化了,也就是一切皆文件的思想
    wenbenwenjian.read()
    yingpanwenjian.write()
    jinchengwenjian.read()
    
    print(wenbenwenjian.all_type)
    print(yingpanwenjian.all_type)
    print(jinchengwenjian.all_type)
    例2

    .

  • 相关阅读:
    移植Linux2.6.38到Tiny6410_1GNandflash
    【转载】Mini6410启动过程
    【转载】Mini2440启动配置文件说明
    【转载】linux2.6内核initrd机制解析
    第十三章 StringTable
    第十二章 执行引擎
    第十一章 直接内存(Direct Memory)
    第十章 对象的实例化、内存布局与访问定位
    第九章 方法区
    第八章 堆
  • 原文地址:https://www.cnblogs.com/tootooman/p/9224585.html
Copyright © 2011-2022 走看看