详解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 列表中的下一个类。

原文地址:https://www.cnblogs.com/value-code/p/8455344.html

时间: 2024-08-30 09:53:07

详解super用法的相关文章

结构体定义 typedef struct 用法详解和用法小结

typedef是类型定义的意思.typedef struct 是为了使用这个结构体方便.具体区别在于:若struct node {}这样来定义结构体的话.在申请node 的变量时,需要这样写,struct node n;若用typedef,可以这样写,typedef struct node{}NODE; .在申请变量时就可以这样写,NODE n;区别就在于使用时,是否可以省去struct这个关键字. 第三篇:struct和typedef struct 分三块来讲述:1 首先:在C中定义一个结构体

ANDROID application详解与用法

1:Application是什么? Application和Activity,Service一样,是android框架的一个系统组件,当android程序启动时系统会创建一个 application对象,用来存储系统的一些信息.通常我们是不需要指定一个Application的,这时系统会自动帮我们创建,如果需要创建自己 的Application,也很简单创建一个类继承 Application并在manifest的application标签中进行注册(只需要给Application标签增加个nam

Linux服务之iptables详解及用法

一.iptables前言 1.什么是防火墙呢? 简单的说,防火墙就是工作于主机或网络的边缘,对于进出的报文根据事先定义的规则作检查,将那些能够被规则所匹配到的报文作出相应处理的组件.防火墙在做信息包过滤决定时,有一套遵循和组成的规则,这些规则存储在专用的信 息包过滤表中,而这些表集成在 Linux 内核中.在信息包过滤表中,规则被分组放在我们所谓的链(chain)中.防火墙分为两种:主机防火墙和网络防火墙. 2.什么是iptables呢? 直观的说,iptables是一个软件程序.真正防火墙组件

ExpandableListView二级分栏详解完美用法

对ExpandableListView控件进行封装(未自定义)直接上代码: 通用ViewHolder类,仅在setImageResource中添加代码 package com.svp.haoyan.expandablelistview.tool; import android.content.Context; import android.graphics.Bitmap; import android.util.SparseArray; import android.view.LayoutInf

1.10-linux三剑客之sed命令详解及用法

内容: 1.sed命令介绍 2.语法格式,常用功能 查询  增加  替换 批量修改文件名 第1章 sed是什么 字符流编辑器 Stream Editor 第2章 sed功能与版本 处理出文本文件,日志,配置文件等 增加,删除,修改,查询 sed  --version sed  -i 修改文件内容 第3章 语法格式 3.1 语法格式 sed [选项] [sed指令] [输入文件] sed -i.bak 's#oldboy#oldgril#g' oldbboy.txt 先备份在修改 -i   ---

struct stat结构体的详解和用法

[cpp] view plaincopy //! 需要包含de头文件 #include <sys/types.h> #include <sys/stat.h> int stat(const char *filename, struct stat *buf); //! prototype,原型 struct stat { dev_t       st_dev;     /* ID of device containing file -文件所在设备的ID*/ ino_t       s

[转]Java程序员从笨鸟到菜鸟之(八十三)细谈Spring(十二)OpenSessionInView详解及用法

首先我们来看一下什么是OpenSessionInView?    在hibernate中使用load方法时,并未把数据真正获取时就关闭了session,当我们真正想获取数据时会迫使load加载数据,而此时session已关闭,所以就会出现异常. 比较典型的是在MVC模式中,我们在M层调用持久层获取数据时(持久层用的是load方法加载数据),当这一调用结束时,session随之关闭,而我们希望在V层使用这些数据,这时才会迫使load加载数据,我们就希望这时的session是open着得,这就是所谓

Net编程 详解DataTable用法【转】

http://www.diybloghome.com/article/16.html DataTable表示一个与内存有关的数据表,可以使用工具栏里面的控件拖放来创建和使用,也可以在编写程序过程中根据需要独立创建和使用,最常见的情况是作为DataSet的成员使用,在这种情况下就需要用在编程过程中根据需要动态创建数据表. 1 代码创建DataTable数据表通过添加对象的方式直接在DataSet中创建数据表,可以通过使用Add方法将DataTable添加到DataSet中,这种是使用控件的可视化添

ServletContext详解 以及用法

ServletContext,是一个全局的储存信息的空间,服务器开始,其就存在,服务器关闭,其才释放.request,一个用户可有多个:session,一个用户一个:而servletContext,所有用户共用一个.所以,为了节省空间,提高效率,ServletContext中,要放必须的.重要的.所有用户需要共享的线程又是安全的一些信息. 换一种方式说吧,运行在Java虚拟机中的每一个Web应用程序都有一个与之相关的Servlet上下文.ServletContext对象是Web服务器中的一个已知