开始之前,先出一道题:

 1 #super函数探讨
 2 class A(object):
 3     def __init__(self):
 4         print 'A.__init__'
 5
 6 class B(A):
 7     def __init__(self):
 8         super(B, self).__init__()
 9         print 'B.__init__'
10
11 class C(A):
12     def __init__(self):
13         super(C, self).__init__()
14         print 'C.__init__'
15
16 class D(B, C):
17     def __init__(self):
18         super(D, self).__init__()
19         print 'D.__init__'
20
21 d = D()  

View Code

上面的运行结果是什么?

是下面的结果吗?

A.__init__
B.__init__
D.__init__

正确答案:

A.__init__
C.__init__
B.__init__
D.__init__

有没有疑惑?super()函数不是调用指定类的父类的方法吗!打印了A.__init__下一句为什么是C.__init__呢?

根本原因是:

super 和父类没有实质性的关联

首先,我们知道新式类采用广度优先算法,我们来看一下上面的继承关系:

那么,Python是如何实现继承的,继承顺序又是由谁决定的呢? 对于你定义的每一个类而已,Python会计算出一个所谓的方法解析顺序(MRO Method Resolution Order)列表。类的继承顺序就是由这个MRO决定的

MRO通过class.__mro__来查看,我们来打印一下上面例子中的MRO:

print D.__mro__

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

注意__mro__是类的属性,实例没有该属性

这个MRO列表就是一个简单的所有基类的线性顺序表。为了实现继承,Python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。

而这个MRO列表的构造是通过一个C3线性化算法来实现的。 它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

1)子类会先于父类被检查

2)多个父类会根据它们在列表中的顺序被检查

3)如果对下一个类存在两个合法的选择,选择第一个父类

好像还是没明白为什么例子中,打印了A.__init__下一句为什么是C.__init__呢?

我们使用一个函数来解释一下super的原理:

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

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

1)获取 inst 的 MRO 列表

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

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

是不是有一种豁然开朗的赶脚!让我们回到例子中,这里我画出了整个流程;

从上面的流程图就可以看出打印的顺序是对的!

了解了super的原理,那么也就可以理解下面这段有趣的代码了:

1)执行下面代码

1 class A(object):
2     def go(self):
3         print 'A go'
4         super(A, self).go()
5
6 a = A()
7 a.go()

View Code

会报错:

AttributeError: 'super' object has no attribute 'go'

2)执行下面代码:

 1 class A(object):
 2     def go(self):
 3         print 'A go'
 4         super(A, self).go()
 5
 6 class B(object):
 7     def go(self):
 8         print 'B go'
 9
10 class C(A, B):
11     pass
12
13 c = C()
14 c.go()

View Code

不会报错,结果为:

A go
B go

充分说明了super 和父类没有实质性的关联

另外,我们想出了super以外,还有一种直接调用父类方法的方法,如下:

 1 #super函数探讨
 2 class A(object):
 3     def __init__(self):
 4         print 'A.__init__'
 5
 6 class B(A):
 7     def __init__(self):
 8         # super(B, self).__init__()
 9         A.__init__(self)
10         print 'B.__init__'
11
12 class C(A):
13     def __init__(self):
14         # super(C, self).__init__()
15         A.__init__(self)
16         print 'C.__init__'
17
18 class D(B, C):
19     def __init__(self):
20         # super(D, self).__init__()
21         B.__init__(self)
22         C.__init__(self)
23         print 'D.__init__'
24
25 d = D()

View Code

为什么不用这种方法呢?我们运行一下,看一下,结果为:

A.__init__
B.__init__
A.__init__
C.__init__
D.__init__

很明显,A的构造函数运行了两次,这不是我们所希望的;所以还是用super吧!

转载于:https://www.cnblogs.com/deeper/p/7453759.html

super函数没有那么简单-super原理剖析相关推荐

  1. (转)简单代码生成器原理剖析(二)

    原文地址:http://www.cnblogs.com/OceanEyes/archive/2012/03/08/codebuilder.html 上篇<简单代码生成器原理剖析(一)>分析 ...

  2. python继承super函数_Python中的super函数如何实现继承?

    本篇文章给大家带来的内容是关于Python 中的super函数如何实现继承?有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. Py 2.x 和 Py 3.x 中有一个很大的区别就是类,无 ...

  3. 简单代码生成器原理剖析(一)

    上篇文章(深入浅出三层架构)分析了简单三层架构的实现.包括Model,DAL(数据访问层),BLL(业务逻辑层)的实现. 实际开发中,由于重复代码的操作,会花费大量时间,如果以代码生成器来自动生成三层 ...

  4. Python super 函数 - Python零基础入门教程

    目录 一.Python super 函数简介 二.Python super 函数语法 三.Python super 函数使用 1.案例一 2.案例二: 四.猜你喜欢 零基础 Python 学习路线推荐 ...

  5. Python super( ) 函数详解

    目录 1 super( ) 的用途 2 了解 super 的基础信息 3 典型用法 3.1 单继承问题 3.2 单继承问题拓展 3.3 重复调用问题 3.4 super(type) 问题 1 supe ...

  6. python3super用法_Python3中的super()函数详解

    关于Python3中的super()函数 我们都知道,在Python3中子类在继承父类的时候,当子类中的方法与父类中的方法重名时,子类中的方法会覆盖父类中的方法, 那么,如果我们想实现同时调用父类和子 ...

  7. pythonsuper函数_认识python中的super函数

    需求分析 在类继承中,存在这么一种情况: class Human(object): def Move(self): print("我会走路...") class Man(Human ...

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

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

  9. pythonsuper多重继承_Python super()函数使用及多重继承

    super()函数可以用于继承父类的方法,语法如下: super(type[, object-or-type]) 虽然super()函数的使用比较简单,但是需要根据单继承和多继承来分析函数的调用关系. ...

最新文章

  1. nginx做方向代理不显示图片的问题
  2. 白盒测试之路径测试练习
  3. 08 - JavaSE之IO流
  4. 以色列对话国际农民丰收节贸易会-万祥军:谋定无中生有
  5. curl php 模拟来源_PHP-Curl模拟HTTPS请求
  6. 豆瓣评分9.4!这一部纪录片,探秘中国的未至之境!
  7. python写接口测试代码_python写运单接口测试(增改查)完整代码
  8. java将图片传为设定编码值显示(可做刺绣)
  9. find命令过滤 no such_Linux中find命令的用法入门
  10. jquery获取元素颜色css('color')的值返回RGB
  11. 项目拉去某个版本的_项目管理的“背后军师”——高层领导
  12. word中插入代码_如何在Word中优雅的插入公式
  13. 软考对程序员的作用,对程序员有多大意义?
  14. c++ 软件下载 Dev cpp下载
  15. 计算机语言底层用汉语拼音设计,对汉语拼音设计方案认识(10页)-原创力文档...
  16. C#反射基础知识实例总结
  17. 一文看懂ARM Cortex-M处理器 ARM Cortex-M 处理器家族介绍和比较
  18. vmware 文件夹共享
  19. e1000e_probe 其实是e1000_probe
  20. Beaglebone Black Root账号问题

热门文章

  1. keil5用jlink不到芯片_你了解JLink、STLink、ULink、JTAG、SWD、SWIM的区别吗
  2. mysql函数及解析,Mysql研究之MySQL常用内置函数完全解析
  3. 【excel】日期函数DateDif
  4. Access to script at ‘xxx‘ from origin ‘null‘ has been blocked by CORS policy: Cross origin requests
  5. from _sqlite3 import ImportError DLL load failed 找不到指定的模块
  6. 简单实现x的n次方pta_学会这四招,原来平均值计算也可以这么简单
  7. 2020年行政区划代码_2020年南宁市行政区划,了解南宁市有几个区,详细数据
  8. sqlite3 c语言编程,SQLite教程(十三):C语言编程实例代码(1)
  9. 计算机技术会议排名,计算机学科会议排名
  10. 文件上传错误:Error setting expression 'uploadImage' with value '[Ljava.lang.String;@5ff8a691'...