• python中的继承


    什么是继承?

    继承是一种创建新的类的方式,新创建的叫子类,继承的叫父类、超类、基类。

    特点:子类可以使用父类的属性(特征、技能)

    继承是类与类之间的关系

    为什么要继承?

    减少代码冗余、提高重用性

    一、单继承

    子类调用父类的一个方法,可以用super():

    class A(object):
        def pp(self):
            print('pp A')
    
    class B(A):
        def pp(self):
            super().pp()
            print("pp B")
    b = B()
    b.pp()

    #结果:
    pp A
    pp B

    super()常用的方法是在__init__()方法中确保父类被正确的初始化了:

    super(cls,inst).__init__()   #cls,init 可以省略
    class A(object):
        def __init__(self):
            self.x = 1
    
    class B(A):
        def __init__(self):
            super(B,self).__init__()
            self.x = self.x +1
            print(self.x)
    b = B()

    #结果
    2

    也可以直接调用父类的一个方法 :

    A.__init__(self)
    class A(object):
        def __init__(self):
            self.x = 1
    
    class B(A):
        def __init__(self):
            A.__init__(self)
            self.x = self.x +1
            print(self.x)
    b = B()

    #结果
    2

    二、多继承

    super().xx方法可以理解为调用了父类中的方法xx,但是其实在单继承中是这样,而多继承中有些区别

    如下:

    class A(object):
        def __init__(self):
            print("Enter A")
    
    class B(A):
        def __init__(self):
            print('Enter B')
            super(B,self).__init__()
            print('Leave B')
    
    class C(A):
        def __init__(self):
            print('Enter C')
            super(C, self).__init__()
            print('Leave C')
    
    class D(B,C):
        def __init__(self):
            print('Enter D')
            super(D,self).__init__()
            print("Leave D")
    
    d = D()

    结果为:

    Enter D
    Enter B
    Enter C
    Enter A
    Leave C
    Leave B
    Leave D

    如果按照原本的理解,是调用了B,C类中的方法,结果不会是这样,那么为什么会这样呢?

    其实是我们理解错了super()

    super()的用法:

    1.super()的本质

      先说说python中如何实现继承---------对于你定义的每一个类,Python会计算出一个所谓的方法解析顺序(MRO)列表。 这个MRO列表就是一个简单的所有基类的线性顺序表。为了实现继承,Python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。

    而这个MRO列表的构造是通过一个C3线性化算法来实现的。 我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

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

    虽然名义上来说super是用来调用父类中的方法,但是super实际上是在MRO表中找到下一个匹配的类。super原型如下:

    def super(cls, inst):
      mro = inst.__class__.mro()
      return mro[mro.index(cls) + 1]

         两个参数 cls 和 inst 分别做了两件事:
         1. inst 负责生成 MRO 的 list
         2. 通过 cls 定位当前 MRO 中的 index, 并返回 mro[index + 1]

    但是根据我们上面说的super本质知道 super 和父类其实没有实质关联,我们就不难理解为什么 enter B 下一句是 enter C 而不是 enter A了(如果认为 super 代表“调用父类的方法”,会想当然的认为下一句应该是enter A)。

    可以用  self.__class__.__mro__ 方法来查询当前MRO

    MRO:

    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

    在我的理解里,一个多继承中的ORM是固定的(只要每个类之间都有继承关系)

    上方例子的中流程:

    首先是class D中,输出“Enter D" , 然后就会调用super方法,super()方法,第一个参数是D,在MRO列表中的下标(index)为0,那么调用的下一个类就是下标为(index+1)的类,即class B,

    那么进入class B,输出"Enter B" ,再次调用super(),此时的index为1,那么调用的下一个类的index为2,即class C,输出“Enter C” , 然后在class C中,调用super(),进入class A,输出“Enter A”,然后回到class C ,输出 "Leave C" , 再回到class B ,输出“Leave B”, 然后回到class D,输出“Leave D”。结束

    当你使用 super() 函数时,Python会在MRO列表上继续搜索下一个类。 只要每个重定义的方法统一使用 super() 并只调用它一次, 那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次。

  • 相关阅读:
    H.264 RTP PAYLOAD 格式
    ARM:移动GPU往PC GPU效能迈进
    汪墩一中复校设想
    jconsole 和jvisualVM 监控远程 spring boot程序
    jenkins 登录远程机器并执行脚本,脚本中有后台执行的程序无法执行解决方法。
    linux下的抓包工具tcpdump
    adb logcat查看某个进程的输出日志
    Flask-SQLAlchemy 中多表链接查询(不使用外键)
    使用cnpm 安装vue.js
    Jmeter在非GUI环境下传递参数(命令行&Jenkins配置)
  • 原文地址:https://www.cnblogs.com/Jokerguigui/p/11758134.html
Copyright © 2020-2023  润新知