Python中super的应用
- 约定
- 单继承
- 多继承
- super 是个类
- 多继承中 super 的工作方式
- 参考资料
约定
在开始之前我们来约定一下本文所使用的 Python 版本。默认用的是 Python 3,也就是说:本文所定义的类都是新式类。如果你用到是 Python 2 的话,记得继承 object:
# 默认, Python 3
class A:
pass # Python 2
class A(object):
pass
Python 3 和 Python 2 的另一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx :
# 默认,Python 3
class B(A):
def add(self, x):
super().add(x) # Python 2
class B(A):
def add(self, x):
super(B, self).add(x)
所以,你如果用的是 Python 2 的话,记得将本文的 super() 替换为 suepr(Class, self) 。
如果还有其他不兼容 Python 2 的情况,我会在文中注明的。
单继承
在单继承中 super 就像大家所想的那样,主要是用来调用父类的方法的。
class A:
def __init__(self):
self.n = 2 def add(self, m):
print('self is {0} @A.add'.format(self))
self.n += m class B(A):
def __init__(self):
self.n = 3 def add(self, m):
print('self is {0} @B.add'.format(self))
super().add(m)
self.n += 3
你觉得执行下面代码后, b.n 的值是多少呢?
b = B()
b.add(2)
print(b.n)
执行结果如下:
self is <__main__.B object at 0x106c49b38> @B.add
self is <__main__.B object at 0x106c49b38> @A.add
8
这个结果说明了两个问题:
- super().add(m) 确实调用了父类 A 的 add 方法。
- super().add(m) 调用父类方法 def add(self, m) 时, 此时父类中 self 并不是父类的实例而是子类的实例, 所以b.add(2) 之后的结果是 5 而不是 4 。
不知道这个结果是否和你想到一样呢?下面我们来看一个多继承的例子。
多继承
这次我们再定义一个 class C,一个 class D:
class C(A):
def __init__(self):
self.n = 4 def add(self, m):
print('self is {0} @C.add'.format(self))
super().add(m)
self.n += 4 class D(B, C):
def __init__(self):
self.n = 5 def add(self, m):
print('self is {0} @D.add'.format(self))
super().add(m)
self.n += 5
下面的代码又输出啥呢?
d = D()
d.add(2)
print(d.n)
这次的输出如下:
self is <__main__.D object at 0x10ce10e48> @D.add
self is <__main__.D object at 0x10ce10e48> @B.add
self is <__main__.D object at 0x10ce10e48> @C.add
self is <__main__.D object at 0x10ce10e48> @A.add
19
你说对了吗?你可能会认为上面代码的输出类似:
self is <__main__.D object at 0x10ce10e48> @D.add
self is <__main__.D object at 0x10ce10e48> @B.add
self is <__main__.D object at 0x10ce10e48> @A.add
15
为什么会跟预期的不一样呢?下面我们将一起来看看 super 的奥秘。
super 是个类
当我们调用 super() 的时候,实际上是实例化了一个 super 类。你没看错, super 是个类,既不是关键字也不是函数等其他数据结构:
>>> class A: pass
...
>>> s = super(A)
>>> type(s)
<class 'super'>
>>>
在大多数情况下, super 包含了两个非常重要的信息: 一个 MRO 以及 MRO 中的一个类。当以如下方式调用 super 时:
super(a_type, obj)
MRO 指的是 type(obj) 的 MRO, MRO 中的那个类就是 a_type , 同时 isinstance(obj, a_type) == True 。
当这样调用时:
super(type1, type2)
MRO 指的是 type2 的 MRO, MRO 中的那个类就是 type1 ,同时 issubclass(type2, type1) == True 。
那么, super() 实际上做了啥呢?简单来说就是:提供一个 MRO 以及一个 MRO 中的类 C , super() 将返回一个从 MRO 中 C 之后的类中查找方法的对象。
也就是说,查找方式时不是像常规方法一样从所有的 MRO 类中查找,而是从 MRO 的 tail 中查找。
举个栗子, 有个 MRO:
[A, B, C, D, E, object]
下面的调用:
super(C, A).foo()
super 只会从 C 之后查找,即: 只会在 D 或 E 或 object 中查找 foo 方法。
多继承中 super 的工作方式
再回到前面的
d = D()
d.add(2)
print(d.n)
现在你可能已经有点眉目,为什么输出会是
self is <__main__.D object at 0x10ce10e48> @D.add
self is <__main__.D object at 0x10ce10e48> @B.add
self is <__main__.D object at 0x10ce10e48> @C.add
self is <__main__.D object at 0x10ce10e48> @A.add
19
了吧 ;)
下面我们来具体分析一下:
- D 的 MRO 是: [D, B, C, A, object] 。 备注: 可以通过 D.mro() (Python 2 使用 D.__mro__ ) 来查看 D 的 MRO 信息)
- 详细的代码分析如下:
class A:
def __init__(self):
self.n = 2 def add(self, m):
# 第四步
# 来自 D.add 中的 super
# self == d, self.n == d.n == 5
print('self is {0} @A.add'.format(self))
self.n += m
# d.n == 7 class B(A):
def __init__(self):
self.n = 3 def add(self, m):
# 第二步
# 来自 D.add 中的 super
# self == d, self.n == d.n == 5
print('self is {0} @B.add'.format(self))
# 等价于 suepr(B, self).add(m)
# self 的 MRO 是 [D, B, C, A, object]
# 从 B 之后的 [C, A, object] 中查找 add 方法
super().add(m) # 第六步
# d.n = 11
self.n += 3
# d.n = 14 class C(A):
def __init__(self):
self.n = 4 def add(self, m):
# 第三步
# 来自 B.add 中的 super
# self == d, self.n == d.n == 5
print('self is {0} @C.add'.format(self))
# 等价于 suepr(C, self).add(m)
# self 的 MRO 是 [D, B, C, A, object]
# 从 C 之后的 [A, object] 中查找 add 方法
super().add(m) # 第五步
# d.n = 7
self.n += 4
# d.n = 11 class D(B, C):
def __init__(self):
self.n = 5 def add(self, m):
# 第一步
print('self is {0} @D.add'.format(self))
# 等价于 super(D, self).add(m)
# self 的 MRO 是 [D, B, C, A, object]
# 从 D 之后的 [B, C, A, object] 中查找 add 方法
super().add(m) # 第七步
# d.n = 14
self.n += 5
# self.n = 19 d = D()
d.add(2)
print(d.n)
调用过程图如下:
D.mro() == [D, B, C, A, object]
d = D()
d.n == 5
d.add(2) class D(B, C): class B(A): class C(A): class A:
def add(self, m): def add(self, m): def add(self, m): def add(self, m):
super().add(m) 1.---> super().add(m) 2.---> super().add(m) 3.---> self.n += m
self.n += 5 <------6. self.n += 3 <----5. self.n += 4 <----4. <--|
(14+5=19) (11+3=14) (7+4=11) (5+2=7)

现在你知道为什么 d.add(2) 后 d.n 的值是 19 了吧 ;
Python中super的应用的更多相关文章
- 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中super函数的用法
之前看python文档的时候发现许多单继承类也用了super()来申明父类,那么这样做有何意义? 从python官网文档对于super的介绍来看,其作用为返回一个代理对象作为代表调用父类或亲类方法.( ...
- python中super()的一些用法
在看python高级编程这本书的时候,在讲到super的时候,产生了一些疑惑,super在python中的用法跟其他的语言有一些不一样的地方,在网上找了一些资料,发现基本上很少有文章能把我的疑惑讲明白 ...
- python中super的理解(转)
原文地址:https://www.zhihu.com/question/20040039 针对你的问题,答案是可以,并没有区别.但是这题下的回答我感觉都不够好. 要谈论 super,首先我们应该无视 ...
- Python中super()的用法
参考链接:https://www.cnblogs.com/shengulong/p/7892266.html super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是 ...
- Python中super详解
转至:https://mozillazg.com/2016/12/python-super-is-not-as-simple-as-you-thought.html 说到 super, 大家可能觉得很 ...
- python中super的使用方法
说白了,super的使用就是要子类要调用父类的方法,我们就用super,那你要有调用的规范,我们明白这个规范就可以了. 在python2和python3中,调用方法不同,注意就是了.Python3.x ...
- python中super的使用
转自:http://python.jobbole.com/86787/ super() 的入门使用 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能, ...
随机推荐
- 主角场景Shader效果:遮挡透明
基本原理:被遮挡的部分关闭深度写入, 显示透明效果:未被遮挡的部分不关闭深度测试,显示正常贴图效果,即使用两个Pass即可. Pass1:关闭深度写入(ZWrite Off),深度测试渲染较远的物体, ...
- 逻辑回归原理_挑战者飞船事故和乳腺癌案例_Python和R_信用评分卡(AAA推荐)
sklearn实战-乳腺癌细胞数据挖掘(博客主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003&a ...
- matlab和C语言实现最小二乘法
参考:https://blog.csdn.net/zengxiantao1994/article/details/70210662 Matlab代码: N = ; x = [ ]; y = [ ]; ...
- HTTP协议(3):HTTP1.1与HTTP1.0的区别
翻了下HTTP1.1的协议标准RFC2616,下面是看到的一些它跟HTTP1.0的差别. 1. Persistent Connection持久连接 在HTTP1.0中,每对Request/Respon ...
- 2017 清北济南考前刷题Day 7 afternoon
期望得分:100+100+30=230 实际得分:100+100+30=230 1. 三向城 题目描述 三向城是一个巨大的城市,之所以叫这个名字,是因为城市中遍布着数不尽的三岔路口.(来自取名力为0的 ...
- HDU 2841 容斥 或 反演
$n,m <= 1e5$ ,$i<=n$,$j<=m$,求$(i⊥j)$对数 /** @Date : 2017-09-26 23:01:05 * @FileName: HDU 284 ...
- sql 2012之后分页查询速度问题
一.SQL Server 2012使用OFFSET/FETCH NEXT分页,比SQL Server 2005/2008中的RowNumber()有显著改进.今天特地作了简单测试,现将过程分享如下: ...
- Donald Ervin Knuth:最年轻的图灵奖高德纳
高德纳(Donald Ervin Knuth,1938年),美国著名计算机科学家,斯坦福大学电脑系荣誉教授.高德纳教授被誉为现代计算机科学的鼻祖,在计算机科学及数学领域发表了多部 具广泛影响的论文和著 ...
- TensorFlow在win10上的安装与使用(三)
本篇博客介绍最经典的手写数字识别Mnist在tf上的应用. Mnist有两种模型,一种是将其数据集看作是没有关系的像素值点,用softmax回归来做.另一种就是利用卷积神经网络,考虑局部图片像素的相关 ...
- CF264B Good Sequences
传送门 Description: 松鼠丽丝特别喜欢n个她称之为“好整数”的整数:a1,a2,……,an.(会输入) 现在,她对“好序列”很感兴趣.如果一个序列x1,x2,...,xk能够满足一下三个条 ...