我们最常见的,可以说几乎唯一能见到的使用super的形式是:

class SubClass(BaseClass):
def method(self):
super(SubClass, self).method()
#do some thing here...

其中,最常见的method()是__init__()

以前做过Java,刚刚接触Python的继承,的确感觉有点奇怪,有时候还能搞混。。。当然这还是因为Java是单继承,只能用接口实现类似多继承的方式,而Python就直接支持多继承。

当我第一次见到这个super()的时候,我想说,这是啥啊?为什么Python的super看起来这么奇怪呢?
super直接指向父类的实例不就得了么?为什么非得搞两个参数?
而且第一个参数还是自己的类名,而不是父类的类名!
既然是自己的类名你还费劲写一遍干嘛,干脆省略不得了?
第二个参数为啥是self?既然是self你省略不得了?
还有,super()返回的是个啥玩意啊,为什么可以.method() ? 难道他返回了一个BaseClass的instance么?
 
今天就来解答这一连串的问题。
 

1)super直接指向父类的实例不就得了么?

首先是不能指向,因为子类实例里面根本就没有一个父类实例,这跟java是不同的。详细看这里
其次是即便像我们想象的,子类实例里有一个叫super的指针,指向父类的实例(这个父类实例在子类实例生成的时候自动生成了,是子类实例的一个‘成员’)。
但是由于多继承的存在,还是会有问题。这也是跟java不同,java不支持多继承,java用接口的方式实现多继承。
举个例子:
当只存在单继承的时候,一切很美好,就像java一样:

你只需要在重写方法的时候,用super去调用父类的方法,然后再做自己的事就可以了。
 
但是在多继承的情况下,一切都不美好了:
 

当艺人展示自己能力的时候,他说,父亲啊,你先展示自己的能力,然后我来!
但是父亲是谁? 他有两个父亲! 总不能写两遍 super.展示自己 吧?
那么我们自然想到,给super搞一个参数不得了,指出super的是哪个父类。
比如 super(歌手).展示自己(),super(演员).展示自己(),好像一切又可以美好了:
 

先不说这种写法多么的丑陋,重复了那么多无意义的、类似的行,单说这种方法根本就行不通。

我们看看如果某个艺人的实例调用了.展示能力() ,将会输出什么:
我是人类,我能走路!
我是歌手,我能唱歌!
我是人类,我能走路!
我是演员,我能演戏!
我是艺人,我能代言广告!
有必要告诉大家两遍你是个人类么?这要是一个又身兼了主持人的艺人,岂不是得大声宣布三次自己是个人类??
这显然是不好的。
 
而且,这只是其一,假设多说了几遍自己是人类你也能忍,那么还有一种情况,更糟。
你比如说,艺人类没有重写 展现自己() 这个方法,当你用艺人的实例去调用 展现自己()的时候,将会发生啥?
不重写的方法自动调用父类的,但是有两个父类呀!调用哪个的呢?任意调用一个(比如按从左到右的顺序)?
那么体现不出他另一个父类的特点呀!比如调用歌手类的,那只能体现出这个艺人既是个歌手,又是个人类,根本体现不出他是个演员!
两个都调用?那万一其中一个父类没有这个方法呢?而且先调用哪个后调用哪个?按照左右顺序么?
总之这样很乱,编译器表示压力很大。
 

 
 
所以,python的super()用了两个参数。
先写在这里:
 
super(SubClass, self).method() 的意思是,根据self去找SubClass的‘父亲’,然后调用这个‘父亲’的method()
 
最最重点的地方来了:对于一个类来说,它的‘父类’到底是谁,取决于站在谁的角度去看。
 
 

‘父亲’之所以加了引号,是因为‘父亲’并不一定是上下级的继承关系,很可能只是兄弟。比如上图中歌手的‘父亲’是‘演员’,但实际上他们是兄弟关系。
所以以后用‘下一个类’来代替这个带引号的‘父亲’。
 
总之,站在不同的实例的角度,看到的‘下一个类’是不同的。
 
这就是super()第二个参数————self 的意义。
如果是一个歌手实例调用的,那么self=歌手实例,super()将站在一个歌手的角度,去找歌手类的‘下一个类’,则会找到人类;

如果是一个艺人实例调用的,那么self=艺人实例,super()将站在一个艺人的角度,去找歌手类的‘下一个类’,则会找到演员。

 
 代码如下:
class People(object):
def show_my_power(self):
print(u"I am a people, I can walk !") class Singer(People):
def show_my_power(self):
super(Singer, self).show_my_power()
print(u"I am a singer, I can sing !") class Actor(People):
def show_my_power(self):
super(Actor, self).show_my_power()
print(u"I am an actor, I can act !") class Artist(Singer, Actor):
pass if __name__ == "__main__":
a = Artist()
a.show_my_power()

运行结果:

I am a people, I can walk !
I am an actor, I can act !
I am a singer, I can sing !
这里需要注意:当一个类从多个类继承的时候,按照从左到右的顺序。
也就是说,站在艺人的角度,首先看到艺人类的‘下一个类’是歌手类,然后歌手类的‘下一个类’是演员类。
这是因为歌手写在了左边:Artist(Singer, Actor)

看一下上面代码的执行过程吧:

由于 super() 绝大多数时候,都在咱们开篇说的这种情况下使用,即在类的定义语句块内部写:super(本类名,self)
所以 python3 做了个简化,如果你在类定义的语句块内写一个不带参数的super(),则相当于写了 super(本类名,self)
 

因为 super() 不光可以用在类的定义内部,所以,这种方便仅在类定义体内部有效。

参考

 

Python面试题之Python的Super方法的更多相关文章

  1. 千万不要错过这几道Python面试题,Python面试题No16

    第1题: python下多线程的限制以及多进程中传递参数的方式? python多线程有个全局解释器锁(global interpreter lock),简称GIL,这个GIL并不是python的特性, ...

  2. Python面试题之Python和Java中Super方法的区别

    python 的 super 是一个函数,需要两个参数,第一个参数是类,第二个参数是实例,返回值是一个类对象. 其意义是:站在参数2这个实例的角度看去, 参数1这个类的‘父亲’是谁,把‘父亲’返回. ...

  3. Python面试题之Python面试题汇总

    在这篇文章中: Python基础篇 1:为什么学习Python 2:通过什么途径学习Python 3:谈谈对Python和其他语言的区别 Python的优势: 4:简述解释型和编译型编程语言 5:Py ...

  4. Python面试题之Python面向对象编程汇总

    面向对象的设计思想是从自然界中来的,因为在自然界中,类(Class)和实例(Instance)的概念是很自然的.Class是一种抽象概念,比如我们定义的Class——Student,是指学生这个概念, ...

  5. python面试题二:Python 基础题

    1.位和字节的关系? Byte 字节 bit 位 1Byte = 8bit 2.b.B.KB.MB.GB 的关系? 1Byte = 8bit KB 1KB=1024B MB 1MB=1024KB GB ...

  6. python面试题之Python支持什么数据类型?

    所属网站分类: 面试经典 > python 作者:外星人入侵 链接:http://www.pythonheidong.com/blog/article/67/ 来源:python黑洞网,专注py ...

  7. python面试题之Python如何实现单例模式?

    #使用__metaclass__(元类)的高级python用法 class Singleton2(type): def __init__(cls, name, bases, dict): super( ...

  8. python面试题三:Python 网络编程与并发

    1 简述 OSI 七层协议. OSI七层协议模型主要是: 应用层(Application):为用户的应用程序(例如电子邮件.文件传输和终端仿真)提供网络服务. 表示层(Presentation):使用 ...

  9. Python面试题之python是一种什么语言及优缺点

    1.说说python是一种什么语言? 参考答案:python是一门动态解释性的强类型定义语言 编译型vs解释型 编译型优点:编译器一般会有预编译的过程对代码进行优化.因为编译只做一次,运行时不需要编译 ...

随机推荐

  1. 一步一步安装Git控件版本工具

    Git是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目.Git的读音为/gɪt/.Git是一个开源的分布式版本控制系统,用以有效.高速的处理从很小到非常大的项目版本管理.[2 ...

  2. python update from 2.6 to 2.7

    1 .wget http://python.org/ftp/python/2.7.3/Python-2.7.3.tar.bz2 2.tar -jxvf Python-2.7.3.tar.bz2 &am ...

  3. nvm-windows 手动安装 nvm use 无效 'node' 不是内部或外部命令,也不是可运行的程序

    按照这两位前辈的教程,安装了nvm-windows. http://www.cnblogs.com/yesyes/p/7403184.html http://blog.csdn.net/jingsi1 ...

  4. ios开源东西

    今天,我们将介绍20个在GitHub上非常受开发者欢迎的iOS开源项目,你准备好了吗? 1. AFNetworking 在众多iOS开源项目中,AFNetworking可以称得上是最受开发者欢迎的库项 ...

  5. 微软Build 2017开发者大会午夜趴

    时间:2017年5月10号半夜 地点:微软中关村会议室 一年一度的Build大会,微软今年特地组织了一波粉丝到“现场”远程观摩keynote直播,同时在新浪直播间里也有相应的专家进行同步翻译和讲(tu ...

  6. 让WebApi支持Namespace

    环境:VS2012 .net 4.0 参考: http://aspnet.codeplex.com/SourceControl/changeset/view/dd207952fa86#Samples/ ...

  7. 分布式计算 要不要把写日志独立成一个Server Remote Procedure Call Protocol

    w https://en.wikipedia.org/wiki/Remote_procedure_call In distributed computing a remote procedure ca ...

  8. android问题总结

    1.当打开eclipse时出现如下窗口(内容如下) Error when loading the SDK: Error: Error parsing \Android\adt-bundle-windo ...

  9. List、Map、Set三个接口,存取元素时,各有什么特点?

    List与Set都是单列元素的集合,它们有一个功共同的父接口Collection. Set里面不允许有重复的元素, 存元素:add方法有一个boolean的返回值,当集合中没有某个元素,此时add方法 ...

  10. Java应用多机器部署定时任务解决方案

    Java多机部署下定时任务的处理方案. 本文转自:http://www.cnblogs.com/xunianchong/p/6958548.html 需求: 有两台服务器同时部署了同一套代码, 代码中 ...