zoukankan      html  css  js  c++  java
  • 类的继承,派生,组合,菱形继承问题,类的多态和多态性

    类的继承

    • 继承是一种新建类的方式,新建的类称为子类,被继承的类称为父类
    • 继承的特性是:子类会遗传父类的属性
    • 继承是类与类之间的关系

    为什么用继承

    继承可以减少代码的冗余

    对象的继承

    • python中支持一个类同时继承多个父类

    • 使用__bases__方法可以获取对象获得的类

    • 在python3中如果一个类没有继承任何类,那么它默认集成object类

    • python2中不会继承object类

    继承与抽象

    继承描述的是子类与父类之间的关系,是一种什么是什么的关系。要找出这种关系,必须先抽象再继承,抽象即抽取类似或者说比较像的部分。

    89-类的继承-抽象图.png

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

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

    89-类的继承-继承图.png

    对象查找属性的顺序

    对象自己-》对象的类-》父类-》父类....

    class Foo:
        def f1(self):
            print('Foo.f1')
    
        def f2(self):
            print('Foo.f2')
            self.f1()
    
    
    class Bar(Foo):
        def f1(self):
            print('Bar.f1')
    
    
    # 对象查找属性的顺序:对象自己-》对象的类-》父类-》父类。。。
    obj = Bar()  # self是obj本身,即找到Bar的f1(),即self.f1()==obj.f1()
    obj.f2()
    
    #Foo.f2
    #Bar.f1
    

    类的派生

    • 派生:子类中新定义的属性的这个过程叫做派生,并且需要记住子类在使用派生的属性时始终以自己的为准

    派生方法1

    class OldboyPeople:
        """由于学生和老师都是人,因此人都有姓名、年龄、性别"""
        school = 'oldboy'
    
        def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.gender = gender
    
    
    class OldboyStudent(OldboyPeople):
        """由于学生类没有独自的__init__()方法,因此不需要声明继承父类的__init__()方法,会自动继承"""
    
        def choose_course(self):
            print('%s is choosing course' % self.name)
    
    
    class OldboyTeacher(OldboyPeople):
        """由于老师类有独自的__init__()方法,因此需要声明继承父类的__init__()"""
    
        def __init__(self, name, age, gender, level):
            OldboyPeople.__init__(self, name, age, gender)
            self.level = level  # 派生
    
        def score(self, stu_obj, num):
            print('%s is scoring' % self.name)
            stu_obj.score = num
    
    
    stu1 = OldboyStudent('tank', 18, 'male')
    tea1 = OldboyTeacher('nick', 18, 'male', 10)
    

    派生方法2

    • 严格以来继承属性查找关系
    • super()会得到一个特殊的对象,该对象就是专门用来访问父类中的属性的(按照继承的关系)
    • super().init(不用为self传值)
    • super的完整用法是super(自己的类名,self),在python2中需要写完整,而python3中可以简写为super()
    class OldboyPeople:
        school = 'oldboy'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    
    class OldboyStudent(OldboyPeople):
        def __init__(self, name, age, sex, stu_id):
            # OldboyPeople.__init__(self,name,age,sex)
            # super(OldboyStudent, self).__init__(name, age, sex)
            super().__init__(name, age, sex)
            self.stu_id = stu_id
    
        def choose_course(self):
            print('%s is choosing course' % self.name)
    
    
    stu1 = OldboyStudent('tank', 19, 'male', 1)
    

    类的组合

    组合就是一个类的对象具备某一个属性,这个属性的值指向另外一个类的对象

    为什么用组合

    组合是用来解决类与类之间代码冗余的问题

    如何用组合

    • 需求:假如我们需要给学生增添课程属性,但是又不是所有的老男孩学生一进学校就有课程属性,课程属性是学生来老男孩后选出来的,也就是说课程需要后期学生们添加进去的
    • 实现思路:如果我们直接在学生中添加课程属性,那么学生刚被定义就需要添加课程属性,这就不符合我们的要求,因此我们可以使用组合能让学生未来添加课程属性
    class Course:
        def __init__(self, name, period, price):
            self.name = name
            self.period = period
            self.price = price
    
        def tell_info(self):
            msg = """
            课程名:%s
            课程周期:%s
            课程价钱:%s
            """ % (self.name, self.period, self.price)
            print(msg)
    
    
    class OldboyPeople:
        school = 'oldboy'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    
    class OldboyStudent(OldboyPeople):
        def __init__(self, name, age, sex, stu_id):
            OldboyPeople.__init__(self, name, age, sex)
            self.stu_id = stu_id
    
        def choose_course(self):
            print('%s is choosing course' % self.name)
    
    
    class OldboyTeacher(OldboyPeople):
        def __init__(self, name, age, sex, level):
            OldboyPeople.__init__(self, name, age, sex)
            self.level = level
    
        def score(self, stu, num):
            stu.score = num
            print('老师[%s]为学生[%s]打分[%s]' % (self.name, stu.name, num))
    
    # 创造课程
    python = Course('python全栈开发', '5mons', 3000)
    python.tell_info()
    

    课程名:python全栈开发
    课程周期:5mons
    课程价钱:3000

    linux = Course('linux运维', '5mons', 800)
    linux.tell_info()
    

    课程名:linux运维
    课程周期:5mons
    课程价钱:800

    # 创造学生与老师
    stu1 = OldboyStudent('tank', 19, 'male', 1)
    tea1 = OldboyTeacher('nick', 18, 'male', 10)
    
    • 组合
    # 将学生、老师与课程对象关联/组合
    stu1.course = python
    tea1.course = linux
    
    stu1.course.tell_info()
    

    课程名:python全栈开发
    课程周期:5mons
    课程价钱:3000

    tea1.course.tell_info()
    

    课程名:linux运维
    课程周期:5mons
    课程价钱:800

    菱形继承问题

    类的分类

    1. 新式类

    • 继承了object的类以及该类的子类,都是新式类
    • python3中所有的类都是新式类

    2. 经典类

    • 没有继承object的类以及该类的子类,都是经典类
    • 只有python2中才有经典类

    在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D)

    如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性

    如果继承关系为菱形结构,即子类的父类最后继承了同一个类,那么属性的查找方式有两种:

    • 经典类下:深度优先
    • 新式类下:广度优先
    • 经典类:一条路走到黑,深度优先
    • 新式类:不找多各类最后继承的同一个类,直接去找下一个父类,广度优先

    可以使用mro()方法来方法来得出子类的继承顺序:print(A.mro())

    类的多态与多态性

    多态

    多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承)

    使用以下定义规定 继承父类的子类必须要有对应的某些方法

    import abc
    
    class Animal(metaclass=abc.ABCMeta):  # 同一类事物:动物
        @abc.abstractmethod  # 上述代码子类是约定俗称的实现这个方法,加上@abc.abstractmethod装饰器后严格控制子类必须实现这个方法
        def talk(self):
            raise AttributeError('子类必须实现这个方法')
    
    
    class People(Animal):  # 动物的形态之一:人
        def talk(self):
            print('say hello')
    
    
    class Dog(Animal):  # 动物的形态之二:狗
        def talk(self):
            print('say wangwang')
    
    
    class Pig(Animal):  # 动物的形态之三:猪
        def talk(self):
            print('say aoao')
    
    
    peo2 = People()
    pig2 = Pig()
    d2 = Dog()
    
    peo2.talk()
    pig2.talk()
    d2.talk()
    

    如果规定只要是会喝水,呼吸的都是动物,那么别的类只要有这两个方法,那么这个类就是动物。

    多个子类去继承父类,那么每一个子类都是这个父类的一种形态。Python中处处都是多态,因为每个对象都继承object。

    多态性

    注意:多态与多态性是两种概念

    多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数,在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方式)。也就是说,每个对象可以用自己的方式去相应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。

    # 多态性:一种调用方式,不同的执行效果(多态性)
    def func(obj):
        obj.run()
    
    
    func(peo1)
    func(pig1)
    func(d1)
    
    人正在走
    pig is walking
    dog is runnin
    

    总的来说,多态性是一个接口(函数func)的多种实现(如obj.run(),obj.talk(),obj.click(),len(obj))

    多态性的好处

    1. 增加了程序的灵活性:以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
    2. 增加了程序额可扩展性:通过继承Animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用

    小结

    多态:同一种事情的多种形态,动物分为人类,猪类(在定义角度)

    多态性:一种调用方式,不同的执行结果(多态性)

  • 相关阅读:
    angularjs+webapi2 跨域Basic 认证授权(二)
    angularjs+webapi2 跨域Basic 认证授权(一)
    记录一些日常windows命令或操作技巧
    unable to locate nuget.exe
    Adobe Acrobat XI Pro闪退原因及解决办法
    货物移动BAPI:BAPI_GOODSMVT_CREATE报错提示“不能执行功能模块 MB_CREATE_GOODS_MOVEMENT”的原因
    ABAP中将Unicode字符串转换成中文的方法
    ABAP中时间戳的处理
    科学吵架修炼指南(摘自凤凰网)
    SAP Web Service简介与配置方法
  • 原文地址:https://www.cnblogs.com/zhoajiahao/p/11052769.html
Copyright © 2011-2022 走看看