zoukankan      html  css  js  c++  java
  • 面向对象的继承和派生

    继承

    1.1什么是继承?

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

    ​ -在python中一个子类可以继承多个父类,(面试的时候可能会问)

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

    1.2继承的作用?

    ​ -减少代码的冗余

    1.3如何实现继承?

    ​ 1.先确认谁是子类,谁是父类

    ​ 2.在定义子类时,子类名(父类名)

    #父类
    class Father1:
        x = 1
        pass
    class Father2:
        pass
    
    #子类
    class Sub(Father1,Father2):
        pass
    #子类查看父类 __bases__
    print(Sub.__bases__)
    print(Sub.x)
    >>>>>>>>>>>>>>>>>
    (<class '__main__.Father1'>, <class '__main__.Father2'>)
    1
    

    2.继承关系

    方法:

    ​ -得先抽象

    ​ -抽取对象之间的相似的部分,总结出类

    ​ -抽取类之间相似的部分,总结出父类

    #问题 代码的冗余
    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(f'老师{self.name}正在修改分数....')
    
    #学生类
    class OldboyStudent:
        def __init__(self,name, age ,sex):
            self.name = name
            self.age = age
            self.sex = sex
        #学生选择课程
        def choose_course(self):
            print(f'学生{self.name}正在选择课程....')
    stu1 = OldboyStudent('huyu',28,'male')
    print(stu1.school,stu1.name,stu1.age,stu1.sex)
    
    tea1 = OldboyTeacher('tank',17,'male')
    print(tea1.school,tea1.name,tea1.age,tea1.sex)
    >>>>>>>>>>>
    oldboy huyu 28 male
    oldboy tank 17 male
    
    #解决代码的冗余的问题  可以用子类父类的来代替
    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('yuyu',20,'female')
    print(stu1.school,stu1.name,stu1.age,stu1.sex)
    
    tea1 = OldboyTeacher('tank',25,'male')
    print(tea1.school,tea1.name,tea1.age,tea1.sex)
    >>>>>>>>>>>>>>>>>>>>>
    oldboy yuyu 20 female
    oldboy tank 25 male
         
    
    

    3.在继承背景下的对象属性的查找顺序

    注意:

    ​ -程序的执行顺序是由上到下,父类必须定义在子类的上方

    ​ -在继承的背景下,对象的属性查找顺序:

    ​ 1.先从对象自己的名称空间中查找;

    ​ 2.对象中没有,从子类的名称空间中查找;

    ​ 3.子类中没有,从父类的名称空间中查找,若父类没有,则会报错!

    #父类
    class Goo:
        x = 10
        pass
    
    #子类
    class Foo(Goo):
        # x = 100
        pass
    foo_obj = Foo()
    foo_obj.x = 20
    print(foo_obj.x)
    print(foo_obj.__dict__)
    print(Foo.__dict__)
    print(Goo.__dict__)
    >>>>>>>>>>>>>>>>>>>
    20  #####如果对象有,则先用对象里面分  如果里面没有,则是用子类的,如果子类里面没有的 则用父类的
    {'x': 20}####这个因为对象名称空间中有
    {'__module__': '__main__', '__doc__': None}####子类的
    {'__module__': '__main__', 'x': 10, '__dict__': <attribute '__dict__' of 'Goo' objects>, '__weakref__': <attribute '__weakref__' of 'Goo' objects>, '__doc__': None}#####这个是父类的
    
    

    4.派生

    定义:指的是子类继承父类的属性和方法,并且派生出自己独有的属性和方法。

    若子类中大方法与父类相同,优先用子类

    #父类
    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.f1()
    bar_obj.f2()
    bar_obj.func()
    >>>>>>>>>>>>>>>
    from Bar.f1...
    from Foo.f2...
    from Bar.func...
    
    #父类
    class Foo():
        def f1(self):
            print('from Foo.f1...')
        def f2(self):#################正常的先调用父类的f2,这个里面的self相当于  									 bar_f1传入的是它的本身
            print('from Foo.f2...')
            
            self.f1()### 相当于bar_obj.f1() 调用的是自身的f1
    #子类
    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...
    
    

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

    #w问题:子类重写父类的__init__导致的代码的更加冗余
    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):
            self.name = name
            self.age = age
            self.sex = sex
            self.sal = sal
        def change_score(self):
            print(f'老师{self.name}修改分数...')
    
    class OldboyStudent(OldboyPeople):
    
        def __init__(self,name,age,sex,girl):
            self.name = name
            self.age = age
            self.sex = sex
            self.girl = girl
        def choose_course(self):
            print(f'老师{self.name}修改分数...')
    
    
    tea1 = OldboyTeacher('tank',17,'male',150000)
    stu1 = OldboyStudent('yaoyuxi',28,'male','美女')
    print(tea1.name,tea1.age,tea1.sex,tea1.sal)
    print(stu1.name,stu1.age,stu1.sex,stu1.girl)
    ###以上方法做的代码比较冗余 我们可以用更加简便的方法来操作
    

    解决上述的问题 ;

    ​ -我们可以用子类重用父亲的属性,并派生出新的属性

    两种方式:

    ​ 1.直接引用父类的——init--为其传参,并添加子类的属性;

    ​ 2.通过super来指向父类的属性super().init

    ​ -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):##把参数要传入
            OldboyPeople.__init__(self,name,age,sex)#####把父类哦传入  参数也要加入 													加入
            self.sal = sal
    
        def change_score(self):
            print(f'老师{self.name}修改分数...')
    
    class OldboyStudent(OldboyPeople):
    
        def __init__(self,name,age,sex,girl):
            OldboyPeople.__init__(self,name,age,sex)
            self.girl = girl
    
        def choose_course(self):
            print(f'老师{self.name}修改分数...')
    tea1 = OldboyTeacher('tank',17,'male',150000)
    print(tea1.name,tea1.age,tea1.sex,tea1.sal)
    stu1 = OldboyStudent('yaoyuxi',28, 'female','美女')
    print(stu1.name,stu1.age,stu1.sex,stu1.girl)
    >>>>>>>>>>>>>>>>>>>
    tank 17 male 150000
    yaoyuxi 28 female 美女
    
    
    #第二种方法
    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__(name,age,sex)####特殊的对象,指向的是父类的名称空间
            								会将调用类传入的对象当作第一个参数传给———											init————()
            self.sal = sal
    
        def change_score(self):
            print(f'老师{self.name}修改分数...')
    
    class OldboyStudent(OldboyPeople):
    
        def __init__(self,name,age,sex,girl):
            super().__init__(name,age,sex)
            self.girl = girl
    
        def choose_course(self):
            print(f'老师{self.name}修改分数...')
    tea1 = OldboyTeacher('tank',17,'male',150000)
    print(tea1.name,tea1.age,tea1.sex,tea1.sal)
    stu1 = OldboyStudent('yaoyuxi',28, 'female','美女')
    print(stu1.name,stu1.age,stu1.sex,stu1.girl)
    >>>>>>>>>>>>>>>>>>>>>>>>
    tank 17 male 150000
    yaoyuxi 28 female 美女
    

    经典式和新式类

    了解类的

    工作上遇不到 ,但是面试上会问的

    ​ -1.新式类

    ​ 1.凡是继承了object的类或者子孙类的都是新式类

    ​ 2.在python3中,所有类默认继承的都是object

    ​ -2.经典类

    ​ 1.在python2中的才会有经典类和新式类之分

    ​ 2.在python2中,凡是没有继承object的类,都是经典类

    class User(object):####这个就是新式类的
        pass
    class Sub(User):
        pass
    print(User.__dict__)
    

    7.super严格遵循mro的继承顺序

    了解的知识点

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

    多继承的情况下:从左向右

    class Father1:
        x = 20
        pass
    class Father2:
        x = 40
        pass
    class Sub(Father1,Father2):
        pass
    obj  = Sub()
    print(Sub.mro())
    
    print(object)
    >>>>>>>>>>>>>>
    [<class '__main__.Sub'>, <class '__main__.Father1'>, <class '__main__.Father2'>, <class 'object'>]  #####这个顺序就是Father1-->Father2从左												向右的查找
    <class 'object'>
    
    # 注意: 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。
    # c.test()
    # '''
    # from A.test
    # from B.test
    # '''
    

    8.mro

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

    mro的查找顺序:

    ​ -新式类:广度优先

    ​ -经典类:深度优先

    # 新式类:
    class A(object):
        def test(self):
            print('from A')
        pass
    
    class B(A):
        def test(self):
            print('from B')
        pass
    
    class C(A):
        def test(self):
            print('from C')
        pass
    class D(B):
        def test(self):
            print('from D')
        pass
    
    class E(C):
        def test(self):
            print('from E')
        pass
    
    class F(D, E):
        def test(self):
            print('from F')
        pass
    
    # F-->D-->B-->E-->C-->A-->object####这个就是新式类的 查找的顺序 最后才找到顶层的A
    # print(F.mro())
    obj = F()
    obj.test()
    >>>>>>>>>>>>>
    from F  ####先从F里面来找
    
    


    这个新式类的属性查找:广度优先

    这个是经典类的属性查找:深度优先

  • 相关阅读:
    Python开发基础-Day11内置函数补充、匿名函数、递归函数
    Python开发基础-Day10生成器表达式形式、面向过程编程、内置函数部分
    Python开发基础-Day9-生成器、三元表达式、列表生成式、生成器表达式
    Python开发基础-Day8-装饰器扩展和迭代器
    Python开发基础-Day5-字符编码、文件处理和函数基础(草稿)
    Python开发基础-Day7-闭包函数和装饰器基础
    Python开发基础-Day6-函数参数、嵌套、返回值、对象、命名空间和作用域
    Android网络课程笔记-----Actionbar的实现方式
    Android网络课程笔记-----自定义控件的方法和技巧
    浅谈android的selector背景选择器
  • 原文地址:https://www.cnblogs.com/bs2019/p/11942021.html
Copyright © 2011-2022 走看看