zoukankan      html  css  js  c++  java
  • python学习笔记 day24 多继承

    1.新式类中多继承----经典的钻石问题

    一个类可以继承多个类,一个类也可以被多个类继承,被继承的类又称为父类,基类或超类;继承父类的类叫子类或派生类;

    一个类在继承多个类时,默认是就近原则,顺序就是在新式类中是广度优先原则;在经典类中是深度优先原则;

    (python3版本中的类都是新式类,python2版本中的类既包括新式类也有经典类,区别是python2版本中的新式类都是继承自Object的)

    1. 先看一个多继承的例子:

    class A():
        def func(self):
            print("A")
    class B(A):
        def func(self):
            print('B')
    class C(A):
        def func(self):
            print("C")
    class D(B,A):
        def func(self):
            print('D')
    d=D()
    d.func()

    运行结果:

    这很明显,虽然D这个类继承了B C但是当实例化D时,对象调用func()方法,但是我自己的类中就有的话当然用自己的~

    2. 当D()这个类中没有func()方法呢,会调用谁呢~

    class A():
        def func(self):
            print("A")
    class B(A):
        def func(self):
            print('B')
    class C(A):
        def func(self):
            print("C")
    class D(B,C):
        pass
        # def func(self):
        #     print('D')
    d=D()
    d.func()

    运行结果:

    因为D()自己的类中没有func()方法,就去父类中找,原则是就近原则,所以会去B这个父类中查找

    3.当B()类中也没有func()方法呢,又会先调用谁呢~

    class A():
        def func(self):
            print("A")
    class B(A):
        pass
        # def func(self):
        #     print('B')
    class C(A):
        def func(self):
            print("C")
    class D(B,C):
        pass
        # def func(self):
        #     print('D')
    d=D()
    d.func()

    运行结果:

    由于D()这个类继承自B C 自己的类中没有func()方法,就去父类B中找,但是B中也没有func()方法,虽然B继承自A 但是此时并没有一直沿着B去找A 这个爷爷类,而是去找了D的另一个父类C ,然后调用C类中的func()方法(这里之所以不去找A是因为广度优先遍历,知道A这个节点 后续也会由C到达A 所以走到B之后直接走的C)(其实最后当C中也找不到相应的方法时就去A中查找;)

    4. 当C()这个类中也没有func()方法时,就去调用A中的方法:

    class A():
        def func(self):
            print("A")
    class B(A):
        pass
        # def func(self):
        #     print('B')
    class C(A):
        pass
        # def func(self):
        #     print("C")
    class D(B,C):
        pass
        # def func(self):
        #     print('D')
    d=D()
    d.func()

    运行结果:

    上面就是经典的多继承中的钻石问题(是这样叫吧)画一下图,表示继承顺序:

    为啥走到B之后不先走A 而是先走C呢 就是因为它知道A这个节点,后续通过C也能到达

    其实我们可以根据子类名.mro()方法查看该子类调用父类时的继承顺序

    print(D.mro())

    2.新式类中多继承----小乌龟

    class F():
        def func(self):
            print("F")
    class A(F):
        def func(self):
            print("A")
    class E(F):
        def func(self):
            print("E")
    class B(A):
        def func(self):
            print('B')
    class C(E):
        pass
        def func(self):
            print("C")
    class D(B,C):
        pass
        def func(self):
            print('D')
    d=D()
    d.func()

    我们按照上面的方法依次注释掉类中相应的方法,然后观察继承顺序:
    发现是  D----> B----->A--->C-----E----->F

    画一下流程图:

    首先当D中有相应的方法时,我们肯定优先调用D类中的方法,如果D中没有相应的方法我们才去D的父类中去查找相应的方法,B C 都是父类,但是按照广度优先,应该先走B 然后当B中没有相应的方法时,应该是走B的父类A 还是走D的父类C呢,其实是应该走A的,因为A如果这个时刻不走的话,走其他节点是无论如何都到不了A的,所以先走A ,然后接下来是走A的父类F还是走D的父类C呢,其实应该走C 因为你发现这个时候不走F 后面仍然有其他途径可以到达F呀,所以此时先走C 然后走E 最后走F

    以上就是新式类中的多继承的继承顺序,就是默认就近原则,顺序是广度优先;而python3中的类都是新式类;python2中既有新式类(继承自Object)也有经典类;

     那对于经典类的多继承继承顺序应该是深度优先!!

    3.经典类中钻石问题:

    经典类中多继承是深度优先,就是在找父类的过程中是沿着一条路走到黑,深度优先

     

    4.经典类中小乌龟问题:

     

    5.多继承中的super():

     子类名.mro()方法可以查看子类继承父类的继承顺序,只可以在新式类中使用;super()方法只可以在python3中的新式类中使用!!

    单继承时,我们提到过在子类中的初始化方法__init__(self,子类中的对象属性)中如果还想使用父类中的相关属性,有两种方法

    1. 父类名.__init__(self,父类中相应的对象属性) 这里的self对象就是代表子类实例化的对象,是必须要传的参数;

    2.super().__init__(父类中的对象属性),这时候super().__init__()这个方法中是不需要传入self参数的(因为super()__init__(父类中的对象属性)中的super()其实就是super(子类名,self))

    单继承时如果自己实现了一个与父类重名的方法,我们如果想在子类的该重名方法中使用父类的该重名方法 也有两种方法

    1. 父类名.方法(self,方法中的其他参数),这里的self参数也是必须要传的;

    2.super().方法名(方法中的其他参数)  这时候是不需要传self参数------》这里是在子类的重名方法内这样写(子类方法中的super()是没有参数的 ,其实是super(子类名,self)省略了而已),当然也可以在类外部写:super(子类名,子类实例化对象).方法名(方法的其他参数)

    现在要讲一种在多继承中使用super() 代表的其实不是父类了,在多继承中,super()的本质已经不是直接找父类,而是根据调用者的节点位置的广度优先顺序查找的,谁在下一个顺序,谁就是super()

    class A():
        def func(self):
            print("A")
    class B(A):
        def func(self):
            super().func()
            print("B")
    class C(A):
        def func(self):
            super().func()
            print("C")
    class D(B,C):
        def func(self):
            super().func()
            print("D")
    d=D()
    d.func()

    运行结果:

    原因就是,super()的本质不是直接找父类,而是根据调用者(这里是d=D() 是D类的实例化对象)节点位置的广度优先顺序(上面已经分析了 在新式类(因为super()只用在新式类)中多继承的继承顺序是广度优先,应该是D,B,C,A)所以首先d.func()执行的D类中定义的func()函数,先执行里面的super().func(),super()指的是B 也就是去执行B.func() 发现B.func()中 也有super().func() 这里的super()指的不是父类,而是调用者节点位置的广度优先顺序,B之后应该是C节点,所以B.func()这里的super().func()就是去执行C.func() ,C.func()函数中的super().func()指的就是A.func() 所以先输出A,,然后C 然后B 最后D;

    talk is cheap,show me the code
  • 相关阅读:
    使用C#编写SqlHelper类
    编译器perspective oo 对象模型(1) 之 初窥c++对象模型
    浅谈 编译器 & 自然语言处理
    基于c#的角色扮演游戏设计与实现
    开源的EtherCAT Master简介
    如何在Windows中编译Linux Unix的代码(采用cygwin)?
    sql拼语句例子
    IOC介绍-手写一个简单的IOC
    protocalBuffer_java版详解(转thanks)
    ProtocalBuffer_数据结构(转thanks)
  • 原文地址:https://www.cnblogs.com/xuanxuanlove/p/9671593.html
Copyright © 2011-2022 走看看