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

    类的继承

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

    为什么用继承

    • 使用继承可以减少代码的冗余

    对象的继承

    • python中支持一个类同时继承多个父类
    class Parent1:
        pass
    
    class Parent2:
        pass
    
    class Sub1(Parent1,Parent2)
        pass
    
    • 查找顺序:先自己-->类-->父类-->父类的父类

    • 缺点:当继承多个的时候,功能与功能之间会混乱,顶多继承一个

    • 属性查找连续

    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()
    obj.f2()
    
    ##打印结果
    Foo.f2
    Bar.f1
    

    类的派生

    • 派生:添加新的属性的同时还有继承父类的所有东西

    派生方法一:

    指名道姓访问某一个类的函数:该方式与继承无关

    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)
    
    
    print(stu1.__dict__) #{'name': 'tank', 'age': 18, 'gender': 'male'}
    
    print(tea1.__dict__) #{'name': 'nick', 'age': 18, 'gender': 'male', 'level': 10}
    
    

    派生方法二

    • 严格以来继承属性查找关系
    • 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)
    
    print(stu1.__dict__) #{'name': 'tank', 'age': 19, 'sex': 'male', 'stu_id': 1}
    
    
    

    类的组合

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

    为什么要用组合

    • 组合是用来解决类与类之间代码冗余的问题
    #简单版 学生选课系统
    
    # 简单的选课系统
    class People:
        def __init__(self, name, gender):
            self.name = name
            self.gender = gender
    
        def eat(self):
            print(f'{self.name}开始吃了')
    
    
    class Student(People):
        def __init__(self, student_id, name, gender):
            self.student_id = student_id
            super(Student, self).__init__(name, gender)
    
        def choose_course(self, course):  # python对象
            self.course = course  # 组合  # 把对象当作变量值来用,当作形参/实参/返回值。
            print(f'{self.name}选课{course.name}成功')
    
    
    class Teacher(People):
        def __init__(self, level, name, gender):
            self.level = level
            super(Teacher, self).__init__(name, gender)
    
        def scored(self, student, course, score):
            print(f'老师{self.name}给{student.name}课程{course.name}打分{score}')
    
    
    class Course:
        def __init__(self, name, price):
            self.name = name
            self.price = price
    
    
    class Admin(People):
        def create_course(self, name, price):
            course = Course(name, price)
            print(f'管理员{self.name}创建了课程{name}')
            return course
    
    
    # 课程
    # python = Course('Python', '8888')
    # linux = Course('Linux', '6666')
    
    # 学生
    zhubajie = Student('01', 'zhubajie', 'male')
    sunwukong = Student('02', 'sunwukong', 'male')
    
    # 老师
    nick = Teacher('1', 'nick', 'male')
    tank = Teacher('2', 'tank', 'female')
    
    # 管理员
    egon = Admin('egon', 'male')
    
    # 业务逻辑
    
    # 1. 创建课程
    python = egon.create_course('python', '8888')
    print(type(python))
    print(python.__dict__)
    linux = egon.create_course('linux', '6666')
    print(linux.__dict__)
    
    # 2. 学生选择课程
    zhubajie.choose_course(python)
    
    
    # 3. 老师给学生打分
    nick.scored(zhubajie,python,'0')
    
    

    菱形继承

    • 类的分类

    1.新式类

    • 继承了object的类以及该类的子类,都是新式类
    • python3中所有的类都是新式类
    1. 经典类
    • 没有继承object的类以及该类的子类,都是经典类
    • 只有python2中才有经典类

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

    • 经典类下:深度优先
    • 新式类下:广度优先

    多态与多态性

    多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承)
    1.序列数据类型有多种形态:字符串,列表,元组
    2.动物有多种形态:人,狗,猪

    # 动物有多种形态:人类、猪、狗(在定义角度)
    class Animal:
        def run(self):  # 子类约定俗称的必须实现这个方法
            raise AttributeError('子类必须实现这个方法')
    
    
    class People(Animal):
        def run(self):
            print('人正在走')
    
    
    class Pig(Animal):
        def run(self):
            print('pig is walking')
    
    
    class Dog(Animal):
        def run(self):
            print('dog is running')
    
    
    peo1 = People()
    pig1 = Pig()
    d1 = Dog()
    
    peo1.run()
    pig1.run()
    d1.run()
    
    #打印结果
    人正在走
    pig is walking
    dog is running
    
    #--------------------------------------------------------
    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()
    
    #打印结果
    say hello
    say aoao
    say wangwang
    
    

    多态性

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

    # 多态性:一种调用方式,不同的执行效果(多态性)
    def func(obj):
        obj.run()
    
    
    func(peo1)
    func(pig1)
    func(d1)
    
    #打印结果
    人正在走
    pig is walking
    dog is running
    #------------------------------------------
    # 多态性依赖于:继承
    # 多态性:定义统一的接口
    def func(obj):  # obj这个参数没有类型限制,可以传入不同类型的值
        obj.talk()  # 调用的逻辑都一样,执行的结果却不一样
    
    
    func(peo2)
    func(pig2)
    func(d2)
    
    #打印结果
    say hello
    say aoao
    say wangwang
    
    #---------------------------------------
    

    多态的好处

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

    class Cat(Animal):  # 属于动物的另外一种形态:猫
        def talk(self):
            print('say miao')
    
    
    def func(animal):  # 对于使用者来说,自己的代码根本无需改动
        animal.talk()
    
    
    cat1 = Cat()  # 实例出一只猫
    func(cat1)  # 甚至连调用方式也无需改变,就能调用猫的talk功能
    
    #打印结果
    say miao
    

    小结

    多态:同一种事物的多种形态,动物分为人类,猪类(在定义角度)
    多态性:一种调用方式,不同的执行效果(多态性)

  • 相关阅读:
    poj3126--Prime Path(广搜)
    iOS中 imageNamed方法 非常多图片占用大量内存问题
    容器+AOP实现动态部署(四)
    SpringBoot整合redis哨兵主从服务
    LINUX安装REDIS集群
    软件安装
    如何优雅地用Redis实现分布式锁
    Redis面试总结
    OAuth2.0 知多少(好)
    一张图搞定OAuth2.0
  • 原文地址:https://www.cnblogs.com/bladecheng/p/11052172.html
Copyright © 2011-2022 走看看