zoukankan      html  css  js  c++  java
  • 29、继承

    一、继承

    1.1、什么是继承

      继承是一种创建新类的方式,新建的类可以称为子类或者派生类,父类可以称为基类或者超类,子类会遗传父类
    1.2、Python中的继承

      python中支持多继承关系,一个子类可以继承一个或者多个父类

    class Parent1(object):
        x=1111
    class Parent2(object):
        pass
    class Sub1(Parent1):                                        # 单继承
        pass
    class Sub2(Parent1,Parent2):                            # 多继承
        pass
    print(Sub1.__bases__)
    print(Sub2.__bases__)
    print(Sub1.x)

    1.3、python2以及python3中继承的区别

      python2

        新类式:继承可了object类的子类

        经典式:没有继承object类的子类

      python3

        python3中只有新类式,没有继承任何类的都会默认继承object类
    1.4、python的多继承

      优点:

        子类可以继承多个父类,最大程度的限制重用代码
      缺点:

        1、违背人的思维习惯,继承表达的是一种什么是什么的关系

        2、代码可读性变差

        3、不建议使用多继承,有肯能会引发菱形问题,扩展性变差
      注:

        如果不可避免的需要使用到多个父类的属性,应该使用mixins

    1.5、为什么要使用继承

      解决类与类之间的代码冗余问题

    1.6、怎么实现继承

      当子类需要的代码都在父类中时,可以直接引用

      当子类需要的代码只有部分在父类时,编写类,再指名道姓的从父类中引用代码例如:

      def __init__(self, name, age, sex, salary, level):               类

      OldboyPeople.__init__(self,name,age, sex)                    

    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')
    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) tea_obj.score()

    二、继承属性的查找

    2.1、有了继承关系之后,对象在查找属性时,会先从自身__dict__里面找,如果没有回去子类中查找,最后到父类中

      例题一:子类中没有找到,在父类中找到,父类的函数下子类和父类中都有,会直接先从子类中读取  

    class Foo:
        def f1(self):
            print('Foo.f1')
    
        def f2(self):
            print('Foo.f2')
            self.f1() # obj.f1()
    
    class Bar(Foo):
        def f1(self):
            print('Bar.f1')
    
    obj=Bar()
    obj.f2()                           #Foo.f2    Foo.f1

    3.2、子类中找不到的情况下,在父类中找到了,接着父类的函数会直接指向子类,如果要强行指向父类中,需要指明道姓的调用父类函数:Foo.f1(self)

    class Foo:
        def f1(self):
            print('Foo.f1')
    
        def f2(self):
            print('Foo.f2')
            Foo.f1(self) # 调用当前类中的f1
    
    class Bar(Foo):
        def f1(self):
            print('Bar.f1')
    
    obj=Bar()
    obj.f2()
    
    # Foo.f2
    # Foo.f1

    3.3、从父类调用时,遇到隐藏属性的类,名字将会变形,但是对外不对内,所以自找到父类中的函数

    class Foo:
        def __f1(self): # _Foo__f1
            print('Foo.f1')
    
        def f2(self):
            print('Foo.f2')
            self.__f1() # self._Foo__f1,# 调用当前类中的f1
    
    class Bar(Foo):
        def __f1(self): # _Bar__f1
            print('Bar.f1')
    
    obj=Bar()
    obj.f2()
    
    # Foo.f2
    # Foo.f1

    四、多继承关系带来的菱形问题

    4.1、菱形问题以及MRO的介绍

      菱形问题指的是有多个父类,父类最终又指向同一个父类

      MRO:指的是类的对象访问属性的查找顺序是根据MRO的显示

    4.2、查找顺序

      非菱形:

        按照子类的父类从左到右的顺序,一个分支一个分支的找下去,

      菱形:

        经典型:深度优先,每一个分支找到底,直到最终的父类,第二个分支将不会找最终的父类

        新类型:广度优先,最后一个分支才会找到最终的父类,其余的父类都会直接跳过

    class G: # 在python2中,未继承object的类及其子类,都是经典类
    # def test(self):
    # print('from G')
    pass

    class E(G):
    # def test(self):
    # print('from E')
    pass

    class F(G):
    def test(self):
    print('from F')

    class B(E):
    # def test(self):
    # print('from B')
    pass

    class C(F):
    def test(self):
    print('from C')

    class D(G):
    def test(self):
    print('from D')

    class A(B,C,D):
    # def test(self):
    # print('from A')
    pass

    # 新式类
    # print(A.mro()) # A->B->E->C->F->D->G->object

    # 经典类:A->B->E->G->C->F->D
    obj = A()
    obj.test() #

    4.3、总结

      多继承要不要用?

      要用,但是需要规避几个问题

      1.继承结构不要过于复杂

      2.推荐使用mixins机制,在多继承的背景下满足什么是什么的关系

    5、mixins机制

      多继承的正确打开方式:mixins

      mixins的核心:在多继承的背景下,尽可能的提升多继承的可读性,也就是让多继承满足人的思维方式===》什么是什么

      汽车和飞机都属于交通工具,其中两种飞机有属于能飞的,所以父类的条件是交通工具和能飞,将能飞这个条件提取出来,单独放在左边,因为新类型最后再回找最终的父类。

    class Vehicle:
        pass
    
    class FlyableMixin:
        def fly(self):
            pass
    
    class CivilAircraft(FlyableMixin,Vehicle):  # 民航飞机
        pass
    
    class Helicopter(FlyableMixin,Vehicle):  # 直升飞机
        pass
    
    class Car(Vehicle):  # 汽车并不会飞,但按照上述继承关系,汽车也能飞了
        pass
    
    
    import socketserver
    # 补充:通常Mixin结果的类放在左边

     六、子类中如何应用父类的功能

      使用super()调用父类提供给自己的方法====》严格依赖继承关系

      调用super()会得到一个特殊的对象,该对象会参考发起属性查找那个类MRO,去当前父类中查找属性(mro中的属性)

    class OldboyPeople:
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
        def f1(self):
            print('%s say hello' %self.name)
    
    
    class Teacher(OldboyPeople):
        def __init__(self,name,age,sex,level,salary):
            # super(Teacher,self).__init__(name,age,sex)
            super().__init__(name,age,sex) # 调用的是方法,自动传入对象
    
            self.level = level
            self.salary=salary
    
    # print(Teacher.mro())
    tea_obj=Teacher('egon',18,'male',10,3000)
    print(tea_obj.__dict__)

      

  • 相关阅读:
    第七章 下
    第七章 上
    第六章 下
    第六章 上
    第五章 下
    linux 系统通过安装包安装mysql 8 步骤(非MariaDB)
    热烈庆祝博客换了新皮肤
    异常处理
    栈计算逆波兰表达式
    栈计算中缀表达式
  • 原文地址:https://www.cnblogs.com/jingpeng/p/12669830.html
Copyright © 2011-2022 走看看