一、问题的发现与提出   在Python类的方法(method)中,要调用父类的某个方法,在Python 2.2以前,通常的写法如代码段1:  代码段1:  class A:   def __init__(self):    print "enter A"    print "leave A"  class B(A):   def __init__(self):    print "enter B"    A.__init__(self)    print "leave B"  >>> b = B()  enter B  enter A  leave A  leave B 即,使用非绑定的类方法(用类名来引用的方法),并在参数列表中,引入待绑定的对象(self),从而达到调用父类的目的。   这样做的缺点是,当一个子类的父类发生变化时(如类B的父类由A变为C时),必须遍历整个类定义,把所有的通过非绑定的方法的类名全部替换过来,例如代码段2,  代码段2:  class B(C):    # A --> C   def __init__(self):    print "enter B"    C.__init__(self) # A --> C    print "leave B" 如果代码简单,这样的改动或许还可以接受。但如果代码量庞大,这样的修改可能是灾难性的。   因此,自Python 2.2开始,Python添加了一个关键字super,来解决这个问题。下面是Python 2.3的官方文档说明:  super(type[, object-or-type])   Return the superclass of type. If the second argument is omitted the super object   returned is unbound. If the second argument is an object, isinstance(obj, type)    must be true. If the second argument is a type, issubclass(type2, type) must be    true. super() only works for new-style classes.   A typical use for calling a cooperative superclass method is:    class C(B):        def meth(self, arg):            super(C, self).meth(arg)   New in version 2.2.   从说明来看,可以把类B改写如代码段3:  代码段3:  class A(object):    # A must be new-style class   def __init__(self):    print "enter A"    print "leave A"  class B(C):     # A --> C   def __init__(self):    print "enter B"    super(B, self).__init__()    print "leave B"   尝试执行上面同样的代码,结果一致,但修改的代码只有一处,把代码的维护量降到最低,是一个不错的用法。因此在我们的开发过程中,super关键字被大量使用,而且一直表现良好。   在我们的印象中,对于super(B, self).__init__()是这样理解的:super(B, self)首先找到B的父类(就是类A),然后把类B的对象self转换为类A的对象(通过某种方式,一直没有考究是什么方式,惭愧),然后“被转换”的类A对象调用自己的__init__函数。考虑到super中只有指明子类的机制,因此,在多继承的类定义中,通常我们保留使用类似代码段1的方法。   有一天某同事设计了一个相对复杂的类体系结构(我们先不要管这个类体系设计得是否合理,仅把这个例子作为一个题目来研究就好),代码如代码段4:  代码段4:  class A(object):   def __init__(self):    print "enter A"    print "leave A"  class B(object):   def __init__(self):    print "enter B"    print "leave B"  class C(A):   def __init__(self):    print "enter C"    super(C, self).__init__()    print "leave C"  class D(A):   def __init__(self):    print "enter D"    super(D, self).__init__()    print "leave D"  class E(B, C):   def __init__(self):    print "enter E"    B.__init__(self)    C.__init__(self)    print "leave E"  class F(E, D):   def __init__(self):    print "enter F"    E.__init__(self)    D.__init__(self)    print "leave F"  >>> f = F()  enter F  enter E  enter B  leave B  enter C  enter D  enter A  leave A  leave D  leave C  leave E  enter D  enter A  leave A  leave D  leave F   明显地,类A和类D的初始化函数被重复调用了2次,这并不是我们所期望的结果!我们所期望的结果是最多只有类A的初始化函数被调用2次——其实这是多继承的类体系必须面对的问题。我们把代码段4的类体系画出来,如下图:     object    |       \    |        A    |      / |    B  C  D     \   /   |       E    |         \   |           F   按我们对super的理解,从图中可以看出,在调用类C的初始化函数时,应该是调用类A的初始化函数,但事实上却调用了类D的初始化函数。好一个诡异的问题!   也就是说,mro中记录了一个类的所有基类的类类型序列。查看mro的记录,发觉包含7个元素,7个类名分别为:  F E B C D A object   从而说明了为什么在C.__init__中使用super(C, self).__init__()会调用类D的初始化函数了。 ???   我们把代码段4改写为:  代码段9:  class A(object):   def __init__(self):    print "enter A"    super(A, self).__init__()  # new    print "leave A"  class B(object):   def __init__(self):    print "enter B"    super(B, self).__init__()  # new    print "leave B"  class C(A):   def __init__(self):    print "enter C"    super(C, self).__init__()    print "leave C"  class D(A):   def __init__(self):    print "enter D"    super(D, self).__init__()    print "leave D"  class E(B, C):   def __init__(self):    print "enter E"    super(E, self).__init__()  # change    print "leave E"  class F(E, D):   def __init__(self):    print "enter F"    super(F, self).__init__()  # change    print "leave F"  >>> f = F()  enter F  enter E  enter B  enter C  enter D  enter A  leave A  leave D  leave C  leave B  leave E  leave F   明显地,F的初始化不仅完成了所有的父类的调用,而且保证了每一个父类的初始化函数只调用一次。 三、延续的讨论   我们再重新看上面的类体系图,如果把每一个类看作图的一个节点,每一个从子类到父类的直接继承关系看作一条有向边,那么该体系图将变为一个有向图。不能发现mro的顺序正好是该有向图的一个拓扑排序序列。   从而,我们得到了另一个结果——Python是如何去处理多继承。支持多继承的传统的面向对象程序语言(如C++)是通过虚拟继承的方式去实现多继承中父类的构造函数被多次调用的问题,而Python则通过mro的方式去处理。   但这给我们一个难题:对于提供类体系的编写者来说,他不知道使用者会怎么使用他的类体系,也就是说,不正确的后续类,可能会导致原有类体系的错误,而且这样的错误非常隐蔽的,也难于发现。 四、小结   1. super并不是一个函数,是一个类名,形如super(B, self)事实上调用了super类的初始化函数,        产生了一个super对象;   2. super类的初始化函数并没有做什么特殊的操作,只是简单记录了类类型和具体实例;   3. super(B, self).func的调用并不是用于调用当前类的父类的func函数;   4. Python的多继承类是通过mro的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数        只调用一次(如果每个类都使用super);   5. 混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一        个父类函数被调用多次。

python super详解_python中super()详解相关推荐

  1. python中的super用法详解_Python中super函数用法实例分析

    本文实例讲述了python中super函数用法.分享给大家供大家参考,具体如下: 这是个高大上的函数,在python装13手册里面介绍过多使用可显得自己是高手 23333. 但其实他还是很重要的. 简 ...

  2. python中的super用法详解_Python中super的用法实例

    super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO).重复调用(钻石继承)等种种问题.总之前人留下的经验就是:保持一致性 ...

  3. python算法和数据结构_Python中的数据结构和算法

    python算法和数据结构 To 至 Leonardo da Vinci 达芬奇(Leonardo da Vinci) 介绍 (Introduction) The purpose of this ar ...

  4. python中正则表达式_Python中正则表达式详解

    正则表达式是用来简洁表达一组字符串的表达式,本文主要和大家分享Python 中正则表达式知识详解,希望能帮助到大家.操作符说明实例.表示任何单个字符 [ ]字符集,单个字符取值范围[abc]表示a或b ...

  5. python菜单怎么做_Python 城市菜单详解(超详解)

    print("--------城市查询系统---------") print("--------按数值进行查询--------") menu={"内蒙 ...

  6. python的继承用法_Python 中的继承之Super用法

    以下Copy自官方文档说明,可点击查看官网源文 翻译内容属于德德自译,有不当之处请指正,勿喷... 翻译括弧中是德德自己理解,通过代码验证的,勿喷... super(type[, object-or- ...

  7. python中superclass是什么_Python中super()函数简介及用法分享

    首先看一下super()函数的定义: super([type [,object-or-type]]) Return a **proxy object** that delegates method c ...

  8. super在python中是什么意思_python中super()的作用是什么

    python中super()的作用是什么 发布时间:2020-08-13 13:59:16 来源:亿速云 阅读:112 作者:小新 这篇文章主要介绍python中super()的作用是什么,文中介绍的 ...

  9. python决策树 多分类_Python中的决策树分类:您需要了解的一切

    python决策树 多分类 什么是决策树? (What is Decision Tree?) A decision tree is a decision support tool that uses ...

最新文章

  1. 福利 | 给你个机会与俞士纶(Philip S. Yu)面对面交流 !(附俞教授论文合集资源)...
  2. Tomcat 相关配置
  3. 你正在用左脑还是右脑思考,请测试下就清楚了。
  4. php 导出word 高度,PHP导出word
  5. SQLServer数据库文件相关知识笔记
  6. python程序设计实验配置_20181235 实验三《Python程序设计》实验报告
  7. opencv-api cvtColor
  8. iOS-项目开发1-UIImage
  9. Pwn2Own 2021温哥华黑客大赛的目标和赏金公布
  10. 无意中发现的MSDN软件下载网站
  11. seaborn—seaborn.distplot绘制直方图和连续密度统计
  12. 基于微信小程序开发——音乐播放器
  13. 粤嵌星计划打卡第三十二天(对象的销毁和垃圾收集机制)(java实现一个权限管理系统)
  14. instantclient php,Oracle 轻量即时客户端Instant Client安装配置
  15. 多开工具,终于给找来了~
  16. pve万兆网卡驱动_网卡的正确选择,避开小白踩坑
  17. 数据库基础技巧及用法
  18. 痞子衡嵌入式:浅析IAR下调试信息输出机制之硬件UART外设
  19. 转贴:【游途道标】明帝国曾经拥有的火炮技术到了满清时期已成为可悲的衰落。
  20. 可折叠手机喂肥了黄牛,但柔性屏的未来从来不止手机

热门文章

  1. c语言判断字符串合法标识符,HDU 2024 C语言合法标识符(以及一些关于输入和ctype.h的内容)...
  2. 互信息python代码_转:标准化互信息NMI计算步骤及其Python实现
  3. Qt中pro文件如何从相对路径导入库
  4. elementui的tree组件页面显示不出数据_[Angular 组件库NG-ZORRO基础入门] -Hacker News: Pagination...
  5. 文档在线编辑组件的发展回顾与开发集成选择问题
  6. Quanergy联手思科为智能交通创建物联网解决方案
  7. Oracle 11g Dataguard 物理备库配置(三)之Dataguard broker配置
  8. java:Map借口及其子类HashMap五,identityHashMap子类
  9. Bitdefender Total Security 2014 Free 6 Months 12 month License Key
  10. 艾伟_转载:.NET设计模式:工厂方法模式(Factory Method)