http://funhacks.net/2016/11/09/super/

super仅被用于新式类

在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 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 线性化算法来实现的

super 原理

super 的工作原理如下(不是很精确,事实上super并不是一个函数,是一个类名,形如super(B, self)事实上调用了super类的初始化函数,产生了一个super对象,而这个对象接近于实例self,所以super(B,self).__init__是实例调用方法,为绑定方法)

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):
print (super(Dog,self).greet) a=Dog('aa')
a.greet()#<bound method Animal.greet of <__main__.Dog object at 0x7f898d22d550>>

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 列表中的下一个类

再说一个容易错的点:

c=4
class a:
c=2
def __init__(self):
print (c) aa=a()#打印是4,而不是2.如果把全局变量的c注释掉,就是第一行注释掉,则报错

转载 你不知道的super的更多相关文章

  1. Python: 你不知道的 super

    https://segmentfault.com/a/1190000007426467 Python: 你不知道的 super 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我 ...

  2. [转载]Python: 你不知道的 super

    原文出处: geekvi super() 的入门使用 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用  ...

  3. (转载)深入super,看Python如何解决钻石继承难题

    1.   Python的继承以及调用父类成员 python子类调用父类成员有2种方法,分别是普通方法和super方法 假设Base是基类 class Base(object): def __init_ ...

  4. 你真的理解Java的this和super吗?

    你不知道的this 很多介绍java的书籍都说this指该对象本身.我们来看下面代码: class Base{ private int i = 3; public Base() { this.disp ...

  5. super 使用以及原理

    用super也很久了,但是一直没有关注过他的原理.最近开始越来越多关注python更底层的实现和奇技淫巧.看到该方法越发使用得多所以也研究了一波 平时单继承可能是我们遇到最多的情况.无非就是类似情况. ...

  6. 关于super的理解,三篇文章支撑起来的

    1.有向图的拓扑排序https://blog.csdn.net/wp1603710463/article/details/50900892 2. Python中MRO算法 http://mp.weix ...

  7. Python零散函数

    1. python json.dumps() json.dump()的区别 注意cat ,是直接输出文件的内容 load和loads都是实现"反序列化",区别在于(以Python为 ...

  8. [PY3]——threading.Event

    Class Event { __init__(self) clear(self) is_set(self) set(self) wait(self,timeout=None) } is_set(sel ...

  9. ATTENTION NETWORK分析

    1. TensorFlowTrainable类 1 class TensorFlowTrainable(object): 2 def __init__(self): 3 self.parameters ...

随机推荐

  1. svn命令行创建和删除分支和tags

    首页 分类首页   目录 原文: http://blog.csdn.net/yangzhongxuan/article/details/7519948 http://zccst.iteye.com/b ...

  2. BugPhobia开发篇章:Beta阶段第VI次Scrum Meeting

    0x01 :Scrum Meeting基本摘要 Beta阶段第六次Scrum Meeting 敏捷开发起始时间 2015/12/18 00:00 A.M. 敏捷开发终止时间 2015/12/18 23 ...

  3. input 清空值。(转载)

    ref顾名思义我们知道,其实它就可以被看座是一个组件的参考,也可以说是一个标识.作为组件的属性,其属性值可以是一个字符串也可以是一个函数. 其实,ref的使用不是必须的.即使是在其适用的场景中也不是非 ...

  4. Docker(九)-Docker创建Selenium容器

    SeleniumHQ官方项目:https://github.com/seleniumHQ/docker-selenium 项目目前快速迭代中. Selenium 这里主要针对的是 Selenium G ...

  5. sysbench的安装与简单使用

    1. 下载sysbench的文件 https://codeload.github.com/akopytov/sysbench/zip/1.0.15 2. 放进linux机器以及进行解压缩 unzip ...

  6. Java超类-java.lang.object

    Java是面向对象的,Object是所有对象的超类(不是继承,也不是实现接口) Object类是所有Java类的祖先.每个类都使用 Object 作为超类.所有对象(包括数组)都实现这个类的方法. 如 ...

  7. MT【195】三次函数

    (2016年清华大学自主招生暨领军计划试题) 已知$x,y,z\in \mathbf{R}$,满足$x+y+z=1,x^2+y^2+z^2=1$,则下列结论正确的有( ) A.$xyz$的最大值为$0 ...

  8. 解析word公式的解决方案(office插入和wps插入不同的解决方案)

    这几天在公司的项目有个需求就是数学公式的导入,而对于word来说,插入的公式xml格式,需要转换为mathML,借用插件MathJax来进行展示,而对于wps插入的公式来说,获取到的是一个wmf图片, ...

  9. bzoj 1824: [JSOI2010]下棋问题

    考虑每次新放一个棋子会产生多少新的矩形,以及减掉多少旧的矩形. 用第$i$个点的坐标把坐标轴分成4个象限. 显然第一问的答案用四个单调栈就能解决. 而且第二问每个矩形的两个端点一定在1,3或2,4象限 ...

  10. 洛谷P3227 切糕

    最小割模板. 题意:你要在一个三维点阵的每个竖条中删去一个点,使得删去的点权和最小. 且相邻(四联通)的两竖条之间删的点的z坐标之差的绝对值不超过D. 解: 首先把这些都串起来,点边转化,就变成最小割 ...