• day29---面向对象编程之继承


    一、什么是继承


    # 继承是一种创建新类的方式。
    新建的类可称为子类派生类,父类又可称为基类超类,子类会遗传父类的属性

    注意:python支持多继承,新建的类可以继承一个或多个父类

    class ParentClass1: #定义父类
        pass
    
    class ParentClass2: #定义父类
        pass
    
    class SubClass1(ParentClass1): #单继承
        pass
    
    class SubClass2(ParentClass1,ParentClass2): #多继承
        pass

    通过类的内置属性__bases__可以查看类继承的所有父类

    print(SubClass2.__bases__)
    
    
    >> (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)

    二、经典类与新式类


    在python2中有新式类和经典类之分

    #新式类:继承了object类的子类,以及该子类的子类子子类
    #经典:没有继承object类的子类,以及该子类的子类子子类

    在python3中没有继承任何类,那么会默认继承object类,所以python3中所有的类都是新式类

    三、多继承


    python多继承的优缺点

    I 优点:子类可以同时遗传多个父类的属性,最大限度地重用代码
    II缺点:1、违背人的思维习惯:继承表达的是一种什么""什么的关系
               2、代码可读性会变差
               3、不建议使用多继承,有可能会引发可恶的菱形问题,扩展性变差,
              如果真的涉及到一个子类不可避免地要重用多个父类的属性,应该使用Mixins

    继承主要是用来解决类与类之间的代码冗余问题

    # 3、如何实现继承
    # # 示范1:类与类之间存在冗余问题
    # class Student:
    #     school='OLDBOY'
    #
    #     def __init__(self,name,age,sex):
    #         self.name=name
    #         self.age=age
    #         self.sex=sex
    #
    #     def choose_course(self):
    #         print('学生%s 正在选课' %self.name)
    #
    #
    # class Teacher:
    #     school='OLDBOY'
    #
    #     def __init__(self,name,age,sex,salary,level):
    #         self.name=name
    #         self.age=age
    #         self.sex=sex
    #         self.salary=salary
    #         self.level=level
    #
    #     def score(self):
    #         print('老师 %s 正在给学生打分' %self.name)
    #
    
    
    # 示范2:基于继承解决类与类之间的冗余问题
    class OldboyPeople:
        school = 'OLDBOY'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    
    class Student(OldboyPeople):
        def choose_course(self):
            print('学生%s 正在选课' % self.name)
    # stu_obj = Student('lili', 18, 'female')
    # print(stu_obj.__dict__)
    # print(stu_obj.school)
    # stu_obj.choose_course()
    
    
    class Teacher(OldboyPeople):
        #           老师的空对象,'egon',18,'male',3000,10
        def __init__(self, name, age, sex, salary, level):
            # 指名道姓地跟父类OldboyPeople去要__init__
            OldboyPeople.__init__(self,name,age, sex)
            self.salary = salary
            self.level = level
    
        def score(self):
            print('老师 %s 正在给学生打分' % self.name)
    
    tea_obj=Teacher('egon',18,'male',3000,10)
    # print(tea_obj.__dict__)
    # print(tea_obj.school)
    
    tea_obj.score()

    四、属性查找


    有了继承关系,对象在查找属性时,先从对象自己的__dict__中找,如果没有则去子类中找,然后再去父类中找

    >>> 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')
    ... 
    >>> b=Bar()
    >>> b.f2()
    Foo.f2
    Bar.f1

    父类如果不想让子类覆盖自己的方法,可以采用双下划线开头的方式将方法设置为私有的

    >>> class Foo:
    ...     def __f1(self): # 变形为_Foo__fa
    ...         print('Foo.f1') 
    ...     def f2(self):
    ...         print('Foo.f2')
    ...         self.__f1() # 变形为self._Foo__fa,因而只会调用自己所在的类中的方法
    ... 
    >>> class Bar(Foo):
    ...     def __f1(self): # 变形为_Bar__f1
    ...         print('Bar.f1')
    ... 
    >>> 
    >>> b=Bar()
    >>> b.f2() #在父类中找到f2方法,进而调用b._Foo__f1()方法,同样是在父类中找到该方法
    Foo.f2
    Foo.f1

    五、菱形问题


    大多数面向对象语言都不支持多继承,而在Python中,一个子类是可以同时继承多个父类的,这固然可以带来一个子类可以对多个不同父类加以重用的好处,但也有可能引发著名的
    Diamond problem菱形问题

    如下图:

    A类在顶部,B类和C类分别位于其下方,D类在底部将两者连接在一起形成菱形。

    继承原理:

    python到底是如何实现继承的呢? 对于你定义的每一个类,Python都会计算出一个方法解析顺序(MRO)列表,该MRO列表就是一个简单的所有基类的线性顺序列表

    python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。 而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

    1.子类会先于父类被检查
    2.多个父类会根据它们在列表中的顺序被检查
    3.如果对下一个类存在两个合法的选择,选择第一个父类

    对于对象

    1.由对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去,
    2.由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去,

    深度优先和广度优先


    如果继承关系为菱形结构,那么经典类与新式类会有不同MRO,分别对应属性的两种查找方式:深度优先和广度优先

    1、经典类

    #当类是经典类时,多继承的情况下,要查找的属性不存在时,会按照深度优先的方式查找下去

    查找顺序:A->B->E->G->C-F-D

    2、新式类

    #当类是新式类时,多继承的情况下,要查找的属性不存在时,会按照广度优先的方式查找下去

    查找顺序:A->B->E->C->F-D->object

    总结:

    # 多继承到底要不用???
    # 要用,但是规避几点问题
    # 1、继承结构尽量不要过于复杂
    # 2、推荐使用mixins机制:在多继承的背景下满足继承的什么"是"什么的关系
  • 相关阅读:
    吴裕雄 python 机器学习——高斯贝叶斯分类器GaussianNB
    吴裕雄 python 机器学习——分类决策树模型
    吴裕雄 python 机器学习——回归决策树模型
    吴裕雄 python 机器学习——线性判断分析LinearDiscriminantAnalysis
    吴裕雄 python 机器学习——逻辑回归
    吴裕雄 python 机器学习——ElasticNet回归
    吴裕雄 python 机器学习——Lasso回归
    吴裕雄 python 机器学习——岭回归
    吴裕雄 python 机器学习——线性回归模型
    【2017 Multi-University Training Contest
  • 原文地址:https://www.cnblogs.com/surpass123/p/12667089.html
Copyright © 2020-2023  润新知