目录

1 super( ) 的用途

2 了解 super 的基础信息

3 典型用法

3.1 单继承问题

3.2 单继承问题拓展

3.3 重复调用问题

3.4 super(type) 问题


1 super( ) 的用途

了解 super() 函数之前,我们首先要知道 super() 的用途是啥?

  • 主要用来在子类中调用父类的方法。
  • 多用于多继承问题中,解决查找顺序(MRO)、重复调用(钻石继承)等种种问题。

2 了解 super 的基础信息

语法格式:

super([type[, object-or-type]])

函数描述:

  • 返回一个代理对象,它会将方法调用委托给 type 的父类或兄弟类。

参数说明:

  • type —— 类,可选参数。
  • object-or-type —— 对象或类,一般是 self,可选参数。

返回值:

  • super object —— 代理对象。

help 帮助信息:

>>> help(super)
Help on class super in module builtins:class super(object)|  super() -> same as super(__class__, <first argument>)|  super(type) -> unbound super object|  super(type, obj) -> bound super object; requires isinstance(obj, type)|  super(type, type2) -> bound super object; requires issubclass(type2, type)|  Typical use to call a cooperative superclass method:|  class C(B):|      def meth(self, arg):|          super().meth(arg)|  This works for class methods too:|  class C(B):|      @classmethod|      def cmeth(cls, arg):|          super().cmeth(arg)... ...
  • super 是一个继承自 object 的类,调用 super() 函数其实就是 super 类的实例化。
  • 根据官方文档的解释 super() 函数返回的对象 —— super object,就是一个代理对象。
  • super() 有四种参数的组合形式。
  • super() 适用于类的静态方法。

3 典型用法

3.1 单继承问题

首先我们看一个最基本的子类调用父类方法的示例:

>>> class A:def funxx(self):print("执行 A 中的 funxx 方法 ... ...")>>> class B(A):def funxx(self):A.funxx(self)       # 通过类名调用父类中的同名方法,self 参数代表 B 类的实例对象 bprint("执行 B 中的 funxx 方法 ... ...")>>> b = B()
>>> b.funxx()
执行 A 中的 funxx 方法 ... ...
执行 B 中的 funxx 方法 ... ...
  • 定义一个继承自 A 类的子类 B,并在 B 类中重写 funxx() 方法,B 中的 funxx() 是对 A 中的 funxx() 功能的拓展。
  • 因为是拓展了 A 类的 funxx() 方法的功能,所以其任然保留了原功能,即要在子类 B 中调用父类的同名方法来实现原有功能。
  • 上面的示例中是通过 A 类类名调用 A 类中的同名方法来实现的,而第一个参数 self 实际传递的是 B 类的实例 b。

使用 super() 函数来实现父类方法的调用:

>>> class A:def funxx(self):print("执行 A 中的 funxx 方法 ... ...")>>> class B(A):def funxx(self):super().funxx()print("执行 B 中的 funxx 方法 ... ...")>>> b = B()
>>> b.funxx()
执行 A 中的 funxx 方法 ... ...
执行 B 中的 funxx 方法 ... ...
  • 通过执行的结果可以看出实现了和普通类名调用的结果是一样的。
  • 在具有单继承的类层级结构中,super 引用父类而不必显式地指定它们的名称,从而令代码更易维护。(官方文档描述)
  • 也就是说,在子类中不再用父类名调用父类方法,而是用一个代理对象调用父类方法,这样当父类名改变或者继承关系发生变化时,不用对每个调用处都进行修改。

3.2 单继承问题拓展

help() 的帮助信息中,也说明了类中使用 super() 不带参数的形式等同于 super(__class__, <first argument>) 这种形式。这也是 Python 2.x 和 Python 3.x 关于 super() 的区别。

改写之前的单继承问题的代码:

>>> class A:def funxx(self):print("执行 A 中的 funxx 方法 ... ...")>>> class B(A):def funxx(self):super(B, self).funxx()print("执行 B 中的 funxx 方法 ... ...")>>> b = B()
>>> b.funxx()
执行 A 中的 funxx 方法 ... ...
执行 B 中的 funxx 方法 ... ...
  • 基本的调用方法 A.funxx(self) ,其中 self 指代实例对象 b。用语言描述为:实例对象 b 通过 A 类名调用方法 funxx()
  • 官方描述:返回一个代理对象,它会将方法调用委托给 type 的父类或兄弟类。用语言描述为:代理对象 super 通过 type 的父类或兄弟类调用其中的方法。
  • 我们发现 super 是通过参数设置来选择调用哪个父类的方法。其中第二个参数给出 MRO(方法解析顺序),也就是搜索目标方法的顺序,第一个参数则给出搜索目标方法的范围。
  • 例如 super(B, self) ,第一个参数为 B,第二个参数 self 为实例 b,其所在类的继承顺序(MRO)为:B→A→object。所以调用时是在 B 的父类 A 中寻找,如找不到目标方法则会在更上一层的 object 中寻找。

示例:

class A:passclass B(A):passclass C(A):def funxx(self):print("找到 funxx() 位于 C 中...")class D(A):passclass E(B, C):passclass F(E, D):def funff(self):print("执行 F 中的 funff()...")super(E, self).funxx()print(f"F 类的 MRO : {F.__mro__}")
f = F()
f.funff()

运行结果:

F 类的 MRO : (<class '__main__.F'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
执行 F 中的 funff()...
找到 funxx() 位于 C 中...
  • 我们可以看出 F 类的 MRO:F→E→B→C→D→A→object。
  • super() 函数的第一个参数为:E,目标是调用 E 类的父类 B 中的 funxx() 方法,可惜 B 类中没找到,在 B 类的兄弟类 C 中找到了,符合要求。

3.3 重复调用问题

重复调用问题 也称 钻石继承问题 或 菱形图问题。

先来看看普通调用方法在:

>>> class A:def __init__(self):print("打印属性 a")>>> class B(A):def __init__(self):print("打印属性 b")A.__init__(self)>>> class C(A):def __init__(self):print("打印属性 c")A.__init__(self)>>> class D(B, C):def __init__(self):print("打印属性 d")B.__init__(self)C.__init__(self)>>> d = D()
打印属性 d
打印属性 b
打印属性 a
打印属性 c
打印属性 a
  • 因为 B,C 都继承自 A,所以当 D 在实例化时,A 的构造函数被执行了两次。这就是所谓的重复调用问题。
  • 很显然,我们只需要调用一次就可以了,重复的调用只会造成资源浪费。

接下来我们使用 super() 函数来调用:

>>> class A:def __init__(self):print("打印属性 a")>>> class B(A):def __init__(self):print("打印属性 b")super().__init__()                # super() 等同于 super(B, self)>>> class C(A):def __init__(self):print("打印属性 c")super().__init__()                # super() 等同于 super(C, self)>>> class D(B, C):def __init__(self):print("打印属性 d")super(D, self).__init__()>>> d = D()
打印属性 d
打印属性 b
打印属性 c
打印属性 a
  • 查看输出结果我们发现虽然解决了重复调用问题,但是输出结果的顺序好像与我们想的有所区别。我们的惯性思维是:先执行 D 类的 __init__() 方法,接着调用 B 类的 __init__() 方法,B 类的构造方法中又调用了父类 A 的 __init_() 方法,然后再是调用 C 类的 __init_() 方法,该方法也调用了父类 A 的 __init__() 方法。所以执行的结果应该是:打印属性 d,打印属性 b,打印属性 a,打印属性 c。
  • 为何结果不是我们想的那样呢,首先我们要知道 D 类中的第二个参数 self 为 D 的实例 d,它提供的 MRO 为:D→B→C→A→object。所以 D 类中的 super() 函数产生的是 d 的代理对象,当其调用父类 B 的 __init__() 时,B 的 super() 的第二个参数为 D 中的 super object,其所提供的 MRO 依旧为:D→B→C→A→object。也就是说 B 中的 super() 调用的是它的上一级 C 中的 __init__() ,而不是 A 中的 __init__()。所以执行的结果是:打印属性 d,打印属性 b,打印属性 c,打印属性 a。

3.4 super(type) 问题

>>> class A:def funxx(self):print("...A...")>>> class B(A):def funxx(self):print("...B...")>>> sa = super(B)
>>> print(sa)
<super: <class 'B'>, NULL>
>>> print(type(sa))
<class 'super'>
  • 可以看出 super(type) 返回的是一个无效的对象,或者是未绑定的 super object。

Python super( ) 函数详解相关推荐

  1. python的super函数详解

    python基础知识 用于类继承的super函数介绍 目录 python基础知识 一.super函数的用途 二.了解super函数的基本信息 三.多继承不重复调用 四.多继承重复调用 总结 一.sup ...

  2. Python hash函数详解

    Python hash函数详解 hash函数功能介绍 hash() 用于获取取一个对象(字符串或者数值等)的哈希值. hash函数的参数必须为不可变类型参数 ​ 因为hash值是唯一且不可变的,如果参 ...

  3. python map函数详解

    python map函数详解 python中有些内置的高阶函数,如map(),filter(),reduce():之所以称其为高阶函数,因为这类函数接受的参数中有一个参数为函数对象. map()函数格 ...

  4. python input函数详解_对Python3中的input函数详解

    下面介绍python3中的input函数及其在python2及pyhton3中的不同. python3中的ininput函数,首先利用help(input)函数查看函数信息: 以上信息说明input函 ...

  5. python average函数详解_python基础之函数详解

    Python基础之函数详解 一.函数的定义 到现在为止,我们已经掌握了Python的基本语法和数据类型等相关基础知识了,以进行一个项目的编写了,这个时候,就会发现,很多代码需要我们进行复制粘贴,这简直 ...

  6. python int函数详解_Python内置函数OCT详解

    英文文档:oct ( x ) Convert an integer number to an octal string. The result is a valid Python expression ...

  7. python average函数详解_python 函数详解

    函数函数是代码的一种组织形式 函数应该能完成一项特定的工作,而且一般一个函数只完成一项工作 有些语言,分函数和过程两个概念,通俗解释是,有返回结果的是函数,无返回结果的叫过程,python不加以区分 ...

  8. python时间函数详解_Python:Numpy库基础分析——详解datetime类型的处理

    原标题:Python:Numpy库基础分析--详解datetime类型的处理 Python:Numpy库基础分析--详解datetime类型的处理 关于时间的处理,Python中自带的处理时间的模块就 ...

  9. Python choices()函数详解、random模块下的常用函数

    random模块下的方法详解: 1.random.random() 随机生成一个[0,1)之间的浮点数. 2.random.randint(a,b) 随机生成[a,b]范围内一个整数. 3.rando ...

最新文章

  1. [转贴]超过80%的80后大学生不知道自己将来要干什么
  2. Shell 与Python的交互
  3. zigbee看门狗综合实验_2.5KW风光互补发电教学实验系统,风能太阳能发电实训装置_搜狐汽车...
  4. log4j2使用笔记
  5. Meteor工作目录的划分
  6. linux系统——fread()与read()函数族区别
  7. 2017年山东省两化融合深度行临沂站成功举办
  8. Hive排名函数入门
  9. BOW( opencv源码)
  10. 需求:vue+svg实现连线功能
  11. java excel导出下载_Java导出excel并下载功能
  12. js判断数组是否为空
  13. win10计算机上的策略禁止用户安装,win10电脑安装摄像头驱动时提示策略禁止安装此设备的解决教程...
  14. 通过两个列表构建字典_我在两个月内以99美元的价格构建了一个电子商务网站!
  15. 高通与NVIDIA在物联网芯片交锋,争相引入AI
  16. VS2019左侧 黄、绿线条 以及 错误波浪线 隐藏
  17. 网站图片怎么优化搜索排名
  18. Bonecraft 界面汉化补丁
  19. 硬件电路设计之电源电路的设计
  20. 第九天 PC端网页特效(轮播图制作)

热门文章

  1. cuda/cudnn/cuda 10.1安装教程
  2. java listiterator_Java笔记--Java的List、Iterator用法
  3. Linux(CentOS)下,各种协议,端口号
  4. 华为畅享6s可以升级鸿蒙,【华为畅享6S评测】华为畅享6S评测:颜值高又好用的千元机就是它了-中关村在线...
  5. linux 用户和组详解
  6. OpenCV小案例——批量图片合成为视频
  7. @Transactional 使用说明
  8. 如何让CFree5.0支持C++11
  9. 超级玛丽3号MAX 达尔文3号,谁才是真正的重疾险王炸?
  10. 接口电路——原理,应用,分类,处理过程