Python: 你不知道的 super
https://segmentfault.com/a/1190000007426467
在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 super
来实现,比如:
class Animal(object):
def __init__(self, name):
self.name = name
def greet(self):
print 'Hello, I am %s.' % self.name
class Dog(Animal):
def greet(self):
super(Dog, self).greet() # Python3 可使用 super().greet()
print 'WangWang...'
在上面,Animal 是父类,Dog 是子类,我们在 Dog 类重定义了 greet
方法,为了能同时实现父类的功能,我们又调用了父类的方法,看下面的使用:
>>> dog = Dog('dog')
>>> dog.greet()
Hello, I am dog.
WangWang..
super
的一个最常见用法可以说是在子类中调用父类的初始化方法了,比如:
class Base(object):
def __init__(self, a, b):
self.a = a
self.b = b
class A(Base):
def __init__(self, a, b, c):
super(A, self).__init__(a, b) # Python3 可使用 super().__init__(a, b)
self.c = c
深入 super()
看了上面的使用,你可能会觉得 super
的使用很简单,无非就是获取了父类,并调用父类的方法。其实,在上面的情况下,super 获得的类刚好是父类,但在其他情况就不一定了,super 其实和父类没有实质性的关联。
让我们看一个稍微复杂的例子,涉及到多重继承,代码如下:
class Base(object):
def __init__(self):
print "enter Base"
print "leave Base"
class A(Base):
def __init__(self):
print "enter A"
super(A, self).__init__()
print "leave A"
class B(Base):
def __init__(self):
print "enter B"
super(B, self).__init__()
print "leave B"
class C(A, B):
def __init__(self):
print "enter C"
super(C, self).__init__()
print "leave C"
其中,Base 是父类,A, B 继承自 Base, C 继承自 A, B,它们的继承关系如下:
Base
/ \
/ \
A B
\ /
\ /
C
现在,让我们看一下使用:
>>> c = C()
enter C
enter A
enter B
enter Base
leave Base
leave B
leave A
leave C
如果你认为 super
代表『调用父类的方法』,那你很可能会疑惑为什么 enter A 的下一句不是 enter Base 而是 enter B。原因是,super
和父类没有实质性的关联,现在让我们搞清 super
是怎么运作的。
MRO 列表
事实上,对于你定义的每一个类,Python 会计算出一个方法解析顺序(Method Resolution Order, MRO)列表,它代表了类继承的顺序,我们可以使用下面的方式获得某个类的 MRO 列表:
>>> C.mro() # or C.__mro__ or C().__class__.mro()
[__main__.C, __main__.A, __main__.B, __main__.Base, object]
那这个 MRO 列表的顺序是怎么定的呢,它是通过一个 C3 线性化算法来实现的,这里我们就不去深究这个算法了,感兴趣的读者可以自己去了解一下,总的来说,一个类的 MRO 列表就是合并所有父类的 MRO 列表,并遵循以下三条原则:
子类永远在父类前面
如果有多个父类,会根据它们在列表中的顺序被检查
如果对下一个类存在两个合法的选择,选择第一个父类
super 原理
super
的工作原理如下:
def super(cls, inst):
mro = inst.__class__.mro()
return mro[mro.index(cls) + 1]
其中,cls 代表类,inst 代表实例,上面的代码做了两件事:
获取 inst 的 MRO 列表
查找 cls 在当前 MRO 列表中的 index, 并返回它的下一个类,即 mro[index + 1]
当你使用 super(cls, inst)
时,Python 会在 inst 的 MRO 列表上搜索 cls 的下一个类。
现在,让我们回到前面的例子。
首先看类 C 的 __init__
方法:
super(C, self).__init__()
这里的 self 是当前 C 的实例,self.__class__.mro() 结果是:
[__main__.C, __main__.A, __main__.B, __main__.Base, object]
可以看到,C 的下一个类是 A,于是,跳到了 A 的 __init__
,这时会打印出 enter A,并执行下面一行代码:
super(A, self).__init__()
注意,这里的 self 也是当前 C 的实例,MRO 列表跟上面是一样的,搜索 A 在 MRO 中的下一个类,发现是 B,于是,跳到了 B 的 __init__
,这时会打印出 enter B,而不是 enter Base。
整个过程还是比较清晰的,关键是要理解 super 的工作方式,而不是想当然地认为 super 调用了父类的方法。
小结
事实上,
super
和父类没有实质性的关联。super(cls, inst)
获得的是 cls 在 inst 的 MRO 列表中的下一个类。
Python: 你不知道的 super的更多相关文章
- [转载]Python: 你不知道的 super
原文出处: geekvi super() 的入门使用 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 ...
- python之super()函数
python之super()函数 python的构造器奇特, 使用魔方. 构造器内对基类对象的初始化同样也很奇特, 奇特到没有半点优雅! 在构造器中使用super(class, instance)返回 ...
- 由Python的super()函数想到的
python-super *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !im ...
- python中super的理解(转)
原文地址:https://www.zhihu.com/question/20040039 针对你的问题,答案是可以,并没有区别.但是这题下的回答我感觉都不够好. 要谈论 super,首先我们应该无视 ...
- Python面试题之Python的Super方法
我们最常见的,可以说几乎唯一能见到的使用super的形式是: class SubClass(BaseClass): def method(self): super(SubClass, self).me ...
- Python’s super() considered super!
如果你没有被Python的super()惊愕过,那么要么是你不了解它的威力,要么就是你不知道如何高效地使用它. 有许多介绍super()的文章,这一篇与其它文章的不同之处在于: 提供了实例 阐述了它的 ...
- python的super深入了解(转)
1.python的继承以及调用父类成员 python子类调用父类成员有2种方法,分别是普通方法和super方法 假设Base是基类 class Base(object): def __init__(s ...
- python中super().__init__和类名.__init__的区别
super().__init__相对于类名.__init__,在单继承上用法基本无差 但在多继承上有区别,super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次 多继承时 ...
- Python中super的用法【转载】
Python中super的用法[转载] 转载dxk_093812 最后发布于2019-02-17 20:12:18 阅读数 1143 收藏 展开 转载自 Python面向对象中super用法与MRO ...
随机推荐
- Python的编码和解码
Python的编码和解码 在不同的国家,存在不同的文字,由于现在的软件都要做到国际化通用,所以必须要有一种语言或编码方式,来实现各种编码的解码,然后重新编码. 在西方国家,没有汉字,只有英文,所以最开 ...
- 浏览器开发者工具----F12 功能介绍
笔者技巧: 看了些其它回答,有些是用来扒图片的,有些是写爬虫的(这个不要看Elements,因为浏览器会对一些不符合规范的标签做补全或者其它处理,最好是Ctrl+U). 图片的话就不要看Network ...
- 美化博客CSS
title: 美化博客CSS date: 2019/01/19 14:28:59 --- 美化博客CSS 可以去这里看下好看的样式 修改下文档的css,博客园是在页面定制CSS代码,我这里修改了下标题 ...
- elk 中kafka启动脚本和配置文件
kafka启动脚本和配置文件 # more kafka #!/bin/sh # Init script for kafka ### BEGIN INIT INFO # Provides: kafka ...
- makefile $@, $^, $<, $? 表示的意义
ref:https://www.cnblogs.com/gamesun/p/3323155.html $@ 表示目标文件$^ 表示所有的依赖文件$< 表示第一个依赖文件$? 表示比目标还 ...
- Java多线程:向线程传递参数的三种方法
在传统的同步开发模式下,当我们调用一个函数时,通过这个函数的参数将数据传入,并通过这个函数的返回值来返回最终的计算结果.但在多线程的异步开发模式下,数据的传递和返回和同步开发模式有很大的区别.由于线程 ...
- Regularity criteria for NSE 6: $u_3,\p_3u_1,\p_3u_2$
In [Zujin Zhang, Jinlu Li, Zheng-an Yao, A remark on the global regularity criterion for the 3D Navi ...
- Regularity criteria for NSE 5: $u_3,\om_3$
In [Zhang, Zujin. Serrin-type regularity criterion for the Navier-Stokes equations involving one vel ...
- 基于vue cli 3.0创建前端项目并安装cube-ui
前提条件: 安装node.js. 国内的开发者最好先配置淘宝镜像. 之后用cnpm来代替npm命令. 项目创建过程: 打开cmd,输入命令进入目标工作空间,以本机项目为例: cd /d d: cd D ...
- 基于redis的cas集群配置
1.cas ticket统一存储 做cas集群首先需要将ticket拿出来,做统一存储,以便每个节点访问到的数据一致.官方提供基于memcached的方案,由于项目需要,需要做计入redis,根据官方 ...