zoukankan      html  css  js  c++  java
  • Python之面向对象的组合、多态、菱形问题、子类中重用父类的两种方式

    一、组合

    '''
    1、什么是组合
        组合就是一个类的对象具备某一个属性,该属性的值是指向另外一个类的对象
    
    
    2、为何用组合
        组合也是用来解决类与类直接代码冗余问题的
    
    3、如何用组合
    
    '''
    # 继承减少代码冗余,但是将类与类进行了强耦合,python不崇尚,所以能不用继承就尽量不用继承
    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))
    
    
    stu1=OldboyStudent('猪哥',19,'male',1)
    tea1=OldboyTeacher('egon',18,'male',10)
    
    stu1.choose_course()          #学生对象选择课程------猪哥 is choosing course
    tea1.score(stu1,100)          #对象的绑定方法--------老师[egon]为学生[猪哥]打分[100]
    print(stu1.__dict__)          #查看学生的字典属性----{'name': '猪哥', 'age': 19, 'sex': 'male', 'stu_id': 1, 'score': 100}
    
    
    
    
    # #定制课程类
    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)         #调用课程对象,产生课程对象,并自动触发__init__函数的执行
    linux=Course('linux运维','5mons',800)
    # python.tell_info()    #课程对象直接绑定课程类下的方法,并将课程对象当做第一个对象自动传入
    # linux.tell_info()
    
    
    # 创造学生与老师-----------------------------对象
    stu1=OldboyStudent('猪哥',19,'male',1)
    tea1=OldboyTeacher('egon',18,'male',10)
    
    # 重点
    # 将学生、老师与课程对象关联/组合-------------将对象之间进行关联
    # --------------------------关键-----------------------------------------------
    stu1.course=python          #---------------将学生对象stu1与课程对象python关联
    tea1.course=linux           #---------------将老师对象stu1与课程对象linux关联
    # --------------------------关键-----------------------------------------------
    '''组合就是一个类的对象具备某一个属性,该属性的值是指向另外一个类的对象'''
    # 即学生类产生的学生对象具备课程的属性,该课程的属性值是指向课程类中的课程对象的
    
    
    stu1.course.tell_info()     #--------------等价于python.tell_info(),会打印出学生的课程信息
    tea1.course.tell_info()     #--------------等价于linux.tell_info(),会打印出老师的课程信息

    二、菱形继承问题

    #coding:utf-8
    '''
    1、菱形继承
        当一个子继承多个父类时,多个父类最终继承了同一个类,称之为菱形继承
    
    2、菱形继承的问题:
        python2区分经典类与新式类,如果子的继承是一个菱形继承,那么经典类与形式的区别为?
            经典类下查找属性:深度优先查找-----------------一条道走到黑
            新式类下查找属性:广度优先查找------------------最后才去找菱形的端点
    '''
    
    class G(object):
        # def test(self):
        #     print('from G')
        pass
    
    class E(G):
        # def test(self):
        #     print('from E')
        pass
    
    class B(E):
        # def test(self):
        #     print('from B')
        pass
    
    class F(G):
        # def test(self):
        #     print('from F')
        pass
    
    class C(F):
        # def test(self):
        #     print('from C')
        pass
    
    class D(G):
        # def test(self):
        #     print('from D')
        pass
    
    class A(B,C,D):
        def test(self):
            print('from A')
        # pass
    
    obj=A()
    #C3算法只试用新式类,经典类不适用
    print(A.mro())  #mro是一种C3算法,[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>]
    obj.test()       #A->B->E-C-F-D->G-object-------对象属性的查找会严格按照mro列表的顺序进行查找

    三、在子类派生的新方法中重用父类功能的两种方式

    # 在子派生的新方法中重用父类功能的两种方式
    # 方式一:与继承无关
    #指名道姓法,直接用:类名.函数名
    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)
    
    
    # 方式二:严格以mro列表继承属性查找关系
    # super()会得到一个特殊的对象,该对象就是专门用来访问父类中的属性的(按照继承的关系)
    # super().__init__(不用为self传值)------------可以理解为super()是一个特殊的对象,所以对象绑定方法有一个自动传值的效果
    # 注意:
    # 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)   #------父类功能重用方法二
            self.stu_id=stu_id
        #定制学生类的函数属性
        def choose_course(self):
            print('%s is choosing course' %self.name)
    
    stu1=OldboyStudent('猪哥',19,'male',1)
    print(stu1.__dict__)  #-------查看学生对象的字典属性,{'name': '猪哥', 'age': 19, 'sex': 'male', 'stu_id': 1}
    print(OldboyStudent.mro()) #------查看学生类的继承关系,[<class '__main__.OldboyStudent'>, <class '__main__.OldboyPeople'>, <class 'object'>]
    
    
    
    # 继承顺序查找再应用:
    class A:
        def f1(self):
            print('A.f1')
    class B:
        def f2(self):
            super().f1()         #B类和A类没有继承关系,但是会按照mro列表,从该类的下一个类继续进行查找,即此时会到A中进行查找
            print('B.f2')
    
    class C(B,A):
        pass
    
    obj=C()
    print(C.mro()) #C-》B->A->object,查看C类的继承关系,[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
    obj.f2()       #对象属性的查找会严格按照mro列表的顺序进行查找,自己的对象没有到自己的类中找,自己的类中没有,到父类中找,此时父类查找的先后顺序就是按照mro列表来的
    
    # 打印结果:
    '''
    A.f1
    B.f2
    '''

    四、多态与多态性

    '''
    1 什么是多态
        多态指的是同一种事物的多种形态
            水-》冰、水蒸气、液态水
            动物-》人、狗、猪
    
    2 为和要用多态
        多态性:
        继承同一个类的多个子类中有相同的方法名
        那么子类产生的对象就可以不用考虑具体的类型而直接调用功能
    
    3 如何用
    '''
    import abc
    class Animal(metaclass=abc.ABCMeta): #定义一个抽象类,规范一个类的类(统一成一套标准)
        @abc.abstractmethod              #装饰器装饰后,意味着但凡继承类该类的方法,函数属性的属性名都必须与父类的函数属性名一致,否则就会报错
        def speak(self):
            pass
        @abc.abstractmethod              子类此时就必须与父类拥有相同的方法名,否则实例化就会报错
        def eat(self):
            pass
    
    # Animal() #强调:父类是用来制定标准的,不能被实例化-------此时实例化就会报错,这并不是python崇尚的,python更多的是一种约定俗成的,而不是硬性的限制
    class People(Animal):
        def speak(self):
            print('say hello')
    
        def eat(self):
            pass
    
    class Dog(Animal):
        def speak(self):
            print('汪汪汪')
    
        def eat(self):
            pass
    class Pig(Animal):
        def speak(self):
            print('哼哼哼')
    
        def eat(self):
            pass
    
    peo1=People()
    dog1=Dog()
    pig1=Pig()
    #
    #继承同一个动物类的多个子类(人、狗、猪类)中有相同的方法名(speakeat),那么子类产生的对象就可以不用考虑具体的类型而直接调用功能
    peo1.speak()      #不用考虑具体的对象类型,而直接调用speak的功能
    dog1.speak()
    pig1.speak()
    
    # -----------------------不用考虑是什么动物来调用speak的函数属性,所以将其封装成一个功能-----------------------------------
    def my_speak(animal):
        animal.speak()
    my_speak(peo1)
    my_speak(dog1)
    my_speak(pig1)
    # -----------------------不用考虑是什么动物来调用speak的函数属性,所以将其封装成一个功能-----------------------------------
    
    
    
    # 不同的数据类型,他们都有统计长度的这个方法,所以我们想到的是将他们制定成一套方法,便于对不同的数据类型进行统计
    l=[1,2,3]
    s='helllo'
    t=(1,2,3)
    
    print(l.__len__())          #用同一种形式去调用的好处就是将其功能封装成一个函数时,只需要传入对象就可以了
    print(s.__len__())          #如果用不同的方法名去统计不同数据类型的长度,这样封装成函数时就需要制定不同的函数去封装
    print(t.__len__())
    
    # def len(obj):
    #     return obj.__len__()
    
    print(len(l)) # l.__len__()
    print(len(s)) #s.__len__()
    print(len(t))
    
    
    
    # python推崇的是鸭子类型,只要你叫的声音像鸭子,并且你走路的样子也像鸭子,那你就是鸭子
    class Disk:
        def read(self):
            print('disk read')
    
        def write(self):
            print('disk wirte')
    
    
    class Process:
        def read(self):
            print('process read')
    
        def write(self):
            print('process wirte')
    
    
    class File:
        def read(self):
            print('file read')
    
        def write(self):
            print('file wirte')
    
    
    
    obj1=Disk()
    obj2=Process()
    obj3=File()
    
    
    
    obj1.read()
    obj1.write()
  • 相关阅读:
    jquery easy ui 学习 (8)basic treegrid
    jquery easy ui 学习 (7) TreeGrid Actions
    jquery easy ui 学习 (6) basic validatebox
    jquery easy ui 学习 (5) windowlayout
    jquery easy ui 学习 (4) window 打开之后 限制操纵后面元素属性
    提示“应用程序无法启动,因为应用程序的并行配置不正确”不能加载 System.Data.SQLite.dll
    visual studio 添加虚线的快捷键
    VS2010打开项目时,出现“已经在解决方案中打开了具有该名称的项目”问题的解决方案
    visual studio 编译时 出现 Files 的值 乱码
    微信 连接被意外关闭
  • 原文地址:https://www.cnblogs.com/sui776265233/p/9234603.html
Copyright © 2011-2022 走看看