zoukankan      html  css  js  c++  java
  • python super详解

    一、super() 的入门使用

      - 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,

      这时,我们就需要调用父类的方法了,可通过使用 super 来实现,比如:

    class Animal(object):
        def __init__(self, name):
            self.name = name
        def greet(self):
            print("Hello, I am %s."  %self.name)
    
    class Dog(Animal):
        def greet(self):
            super().greet()
            print('WangWang...')
    
    dog = Dog('Teddy')
    dog.greet()
    # Hello, I am dog.
    # WangWang..

      - 在上面,Animal 是父类,Dog 是子类,我们在 Dog 类重定义了 greet 方法,为了能同时实现父类的功能,我们又调用了父类的方法。

      - super 的一个最常见用法可以说是在子类中调用父类的初始化方法了,比如:

    class Base(object):
        def __init__(self, a, b):
            self.a = a
            self.b = b
     
    class A(Base):
        def __init__(self, a, b, c):
            super().__init__(a, b)
            self.c = c

    二、深入super()

      - 其实super并非只是获取父类,调用父类的方法,super其实和父类没有实质性的关联。  

      让我们看一个稍微复杂的例子,涉及到多重继承,代码如下:

    class Base(object):
        def __init__(self):
            print("enter Base")
            print("leave Base")
     
    class A(Base):
        def __init__(self):
            print("enter A")
            super(A, self).__init__()
            print("leave A")
     
    class B(Base):
        def __init__(self):
            print("enter B")
            super(B, self).__init__()
            print("leave B")
     
    class C(A, B):
        def __init__(self):
            print("enter C")
            super(C, self).__init__()
            print("leave C")

      其中,Base 是父类,A, B 继承自 Base, C 继承自 A, B;

      使用起来:

    c=C()
    """
    运行结果为
    enter C
    enter A
    enter B
    enter Base
    leave Base
    leave B
    leave A
    leave C
    """

      - 如果你认为 super 代表『调用父类的方法』,那你很可能会疑惑为什么 enter A 的下一句不是 enter Base

      而是 enter B。原因是,super 和父类没有实质性的关联,现在让我们搞清 super 是怎么运作的。

    三、MRO列表

      - 事实上,对于你定义的每一个类,Python 会计算出一个方法解析顺序(Method Resolution Order, MRO)

      列表它代表了类继承的顺序,我们可以使用下面的方式获得某个类的 MRO 列表:

    print(C.mro())   # or C.__mro__ or C().__class__.mro()
    # [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]

      - MRO列表的顺序是通过一个 C3 线性化算法来实现的,这里我们就不去深究这个算法了,

      总的来说,一个类的 MRO 列表就是合并所有父类的 MRO 列表,并遵循以下三条原则:

    • 子类永远在父类前面
    • 如果有多个父类,会根据它们在列表中的顺序被检查
    • 如果对下一个类存在两个合法的选择,选择第一个父类

    四、super原理 

      super的工作原理如下:

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

      其中,cls 代表类,inst 代表实例,上面的代码做了两件事:

    • 获取 inst 的 MRO 列表
    • 查找 cls 在当前 MRO 列表中的 index, 并返回它的下一个类,即 mro[index + 1]

      当你使用 super(cls, inst) 时,Python 会在 inst 的 MRO 列表上搜索 cls 的下一个类。

      首先看类 C 的 __init__ 方法:

    super(C, self).__init__()

      这里的 self 是当前 C 的实例,self.__class__.mro() 结果是:

    [__main__.C, __main__.A, __main__.B, __main__.Base, object]

      可以看到,C 的下一个类是 A,于是,跳到了 A 的 __init__,这时会打印出 enter A,并执行下面一行代码:

    super(A, self).__init__()

      - 注意,这里的 self 也是当前 C 的实例,MRO 列表跟上面是一样的,搜索 A 在 MRO 中的下一个类,

      发现是 B,于是,跳到了 B 的 __init__,这时会打印出 enter B,而不是 enter Base。

    小结

    • 事实上,super 和父类没有实质性的关联。
    • super(cls, inst) 获得的是 cls 在 inst 的 MRO 列表中的下一个类。
  • 相关阅读:
    java数据类型
    索引的种类和优缺点
    IntelliJ IDEA 自动导入快捷键
    KTV点歌系统------LinkedList
    KTV 点歌系统------ArrayList
    超市购物程序
    awk 入门教程
    Git 分支开发规范
    私有镜像仓库Harbor设置https、http访问
    私有镜像仓库Harbor部署
  • 原文地址:https://www.cnblogs.com/value-code/p/8455344.html
Copyright © 2011-2022 走看看