Python学习笔记之Python的Super方法

我们最常见的,可以说几乎唯一能见到的使用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() 不光可以用在类的定义内部,所以,这种方便仅在类定义体内部有效。

参考

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张善友的专栏

弹出式模态窗体选择文本控件

2006年就要到来了,最近比较忙,很少更新blog,今天发一个模态窗体选择文本控件辞旧迎新.新年在发几个asp.net2.0 webPart控件同各位分享: ...

1907
来自专栏c#开发者

about store RecordField submit emptystring issue

operate screenshot When click save button submit to change,trace store before...

3447
来自专栏xingoo, 一个梦想做发明家的程序员

【插件开发】—— 6 SWT 复杂控件使用以及布局

前文回顾: 1 插件学习篇 2 简单的建立插件工程以及模型文件分析 3 利用扩展点,开发透视图 4 SWT编程须知 5 SWT简单控件的使用与布局搭...

2349
来自专栏菩提树下的杨过

Silverlight:利用异步加载Xap实现自定义loading效果

关键点: 1.利用WebClient的DownloadProgressChanged事件更新下载进度 2.下载完成后,分析Xap包的程序集Assembly信息 ...

18610
来自专栏跟着阿笨一起玩NET

使用延迟的FileSystemWatcher来避免重复触发事件

  程序里需要监视某个目录下的文件变化情况: 一旦目录中出现新文件或者旧的文件被覆盖,程序需要读取文件内容并进行处理;但在实际处理中发现当一个文件产生变化时,C...

912
来自专栏张善友的专栏

通过SmtpClient发送Exchange会议邮件

看到C#中调用Outlook API 发起会议 ,这个完全可以用SMTP方式实现的,下面我的项目中使用的代码: 对于.NET而言,从2.0开始,发邮件已经是一件...

1949
来自专栏木宛城主

曾今的代码系列——自己的分页控件+存储过程实现分页

项目里面的测试代码,仅供参考 LoginByAjax <title>Ajax登陆</title> <script src="Scripts/c...

1865
来自专栏自由而无用的灵魂的碎碎念

小项目分享---混色器

编写代码的同志们一般懂美术的就少了,偶也是,什么色轮、三维加色等等。虽然看过一些书籍(如内田广由纪的《配色基础原理》),不过还是一知半解的。

983
来自专栏我和未来有约会

Silverlight制作逐帧动画 v2 - part2

Silverlight制作逐帧动画 v2 - part2 在这里完善了一下算法,加入了fps的机制进去。 private string[] ...

1896
来自专栏hbbliyong

socket 通信 多线程调用窗体(委托)的几个知识点,记录在案,以备查阅

1.socket 通信传输汉字的方法:Encoding.GetEncoding("GB2312").GetString(Receivebyte) 发送接收都这样...

2737

扫码关注云+社区