zoukankan      html  css  js  c++  java
  • 继承与派生

    继承与派生

    一、继承

    • 继承是一种新建类的方式,新建的类称之为子类或派生类,继承的父类称之为基类或超类

      ​ 在python中,一个子类可以继承多个父类

      ​ 在其他语言中,一个子类只能继承一个父类

    • 继承的作用

      • 减少代码的冗余
    • 如何实现继承

      • 先确认谁是子类,谁是父类
      • 在定义子类时,子类名(父类名)
    class Father1:
        pass
    class Father2:
        pass
    class Father3:
        pass
    # 子类
    class Sub(Father1, Father2, Father3):
        pass
    # 子类 .__bases__ 查看父类
    print(Sub.__bases__)
    print(Sub.x)
    

    二、 如何寻找继承关系

    • 确认谁是子类
      • 对象——>子类——>父类
    • 得先抽象,再继承
      • 抽取对象之间相似的部分,总结出类
      • 抽取类之间相似的部分,总结出父类
    # 问题: 代码冗余
    # 老师类
    class OldboyTeacher:
        school = 'oldboy'
        country = 'China'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        # 老师修改分数
        def change_score(self):
            print ('老师%s正在修改分数...' % self.name)
    
    #学生类
    class OldboyStudent:
        school = 'oldboy'
        country = 'China'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        # 学生选择课程
        def choose_course(self):
            print ('学生%s正在选择课程' % self.name)
    
    stu1 = OldboyStudent('maomao', 18, '男')
    print (stu1.school, stu1.name, stu1.age, stu1.sex)
    
    tea1 = OldboyTeacher('tank', 28, '男')
    print (tea1.school, tea1.name, tea1.age, tea1.sex)
    

    上面的代码看起来冗余很多,所有有了以下的解决办法

    # 解决代码冗余问题
    # 老男孩人类
    class OldboyPeople:
        school = 'oldboy'
        country = 'China'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    # 老师类
    class OldboyTeacher(OldboyPeople):
        # 老师修改分数
        def change_score(self):
            print (f'老师{self.name}正在修改分数...')
    
    # 学生类
    class OldboyStudent(OldboyPeople):
        # 学生选择课程
        def choose_course(self):
            print (f'学生{self.name}正在选择课程...')
    
    stu1 = OldboyStudent('maomao', 18, '男')
    print (stu1.school, stu1.name, stu1.age, stu1.sex)
    tea1 = OldboyTeacher('tank', 28, '男')
    print(tea1.school, tea1.name, tea1.age, tea1.sex)
    

    三、在继承背景下对对象属性的查找顺序

    注意:程序的执行顺序是由上到下,所以父类必须定义在子类的上方

    • 在继承背景下,对象属性的查找顺序:
      • 先从对象自己的名称空间中查找
      • 对象中没有,从子类的名称空间中查找
      • 子类中没有,从父类的名称空间中查找,若父类没有,则会报错
    # 父类
    class Goo:
        x = 10
    # 子类
    class Foo(Goo):
        x = 100
    foo_obj = Foo()
    

    四、 派生

    派生:指的是紫萼里继承父类的属性和方法,并且派生出自己独有的属性与方法

    如果子类中的方法名与父类的相同,优先使用子类的

    # 父类
    class Foo:
        def f1(self):
            print ('from FOO.f1...')
    
        def f2(self):
            print ('from Foo.f2...')
    
    # 子类
    class Bar(Foo):
        def f1(self):
            print ('from Bar.f1...')
    
        def func(self):
            print ('from Bar.func...')
    # 派生后继承关系查找验证
    bar_obj = Bar()
    bar_obj.f2()
    # 结果
        from Foo.f2...
        from Bar.f1...
    

    五、重用

    • 子类继承父类,派生出自己的属性和方法,并且重用父类的属性与方法

    问题就是: 子类重写父类中的__init__导致代码更加冗余

    解决问题:子类重用父类的属性,并派生出新的属性

    • 两种解决方式
      • 直接应用父类的__init__为其传参,并添加子类的属性
      • 通过super来指向父类的属性
        • super() 是一个特殊的类,调用super得到一个对象,该对象指向父类的名称空间

    注意:使用哪一种都是可以的,但是不可以两种混合使用

    # 方式二
    class OldboyPeople:
        school = 'oldboy'
        
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
            
    class OldboyTeacher(OldboyPeople):
        def __init__(self, name, age, sex, sal):
            # super()——>特殊的对象——>对象.属性——>父类的名称空间
            # 会将调用类传入的对象当作第一个参数传给__init__()
            super().__init__(name, age, sex)
            self.sal = sal
            
        def change_score(self):
            print (f'老师{self.name}正在修改分数...')
            
    class OldboyStudent(OldboyPeople):
        def __init__(self, name, age, sex, home):
            super().__init__(name, age, sex)
            self.home = home
            
        def choose_course(self):
            print (f'学生{self.name}正在选择课程...')
            
    tea1 = OldboyTeacher('tank', 18, 'male', 20000)
    print (tea1.name,tea1.age,tea1.sex,tea1.sal)
    stu1 = OldboyStudent('maomao', 18, 'female', '上海市')
    print (stu1.name,stu1.age,stu1.sex,stu1.home)
    

    super的方式就可以避免很多的冗余代码,每个子类下都不需要再重新写self

    六、 经典类与新式类

    • 新式类
      • 凡是继承object的类或子孙都是新式类
      • 在python3中所有的类都默认继承object
    • 经典类
      • 在python2中才会有经典类与新式类之分
      • 在python2中,凡是没有继承object的类,都是经典类
    class User(object):
        pass
    
    class User:
        x = 10
        pass
    
    class Sub(User):
        pass
    

    七、mro继承顺序

    调用mro返回的是一个继承序列

    super的继承顺序严格遵循mro继承序列

    class Father1:
        x = 10
        
    class Father2:
        x = 20
        # 多继承的情况下,从左到右
    class Sub(Father1, Father2):
        def __init__(self):
            print (super().__delattr__)
            
    print (Sub.mro())
    obj = Sub()
    print (object)
    

    python3中提供了一个查找新式类查找顺序的内置方法

    ​ mro():会把当前类的继承关系列出来

    # 注意:super()会严格按照mro列表的顺序往后查找
    class A:
        def test(self):
            print ('from A test')
            super().test()
    
    class B:
        def test(self):
            print ('from B.test')
    
    class C(A,B):
        pass
    c =C()
    # 检查super的继承顺序
    print (C.mro())
    
    # 去A找,有的话打印,然后super又执行了test,根据mro中查找打印B类中的test
    

    八、 钻石继承(菱形继承)

    多继承的情况下,造成“钻石继承”

    • mro的查找顺序
      • 新式类
        • 广度优先
      • 经典类
        • 深度优先

  • 相关阅读:
    关于jstl taglib的错误 Can not find the tag library descriptor for “http://java.sun.com/jstl/core”
    Hibernate复合主键的注解
    最详细的Log4j使用教程
    Ajax 完整教程 (转)
    Servlet3.0学习总结(一)——使用注解标注Servlet
    掌握Tiles 框架 (一)---Tiles入门和Tiles 框架和体系结构
    web.xml文件的作用及基本配置
    Axis 生成客户端client stub文件
    HTML5必须知道的那些事
    XFire创建WebService实例应用
  • 原文地址:https://www.cnblogs.com/YGZICO/p/11959700.html
Copyright © 2011-2022 走看看