Python super( ) 函数详解
目录
1 super( ) 的用途
2 了解 super 的基础信息
3 典型用法
3.1 单继承问题
3.2 单继承问题拓展
3.3 重复调用问题
3.4 super(type) 问题
1 super( ) 的用途
了解 super() 函数之前,我们首先要知道 super() 的用途是啥?
2 了解 super 的基础信息
语法格式:
super([type[, object-or-type]])
函数描述:
参数说明:
返回值:
help 帮助信息:
>>> help(super)
Help on class super in module builtins:
class super(object)
| super() -> same as super(__class__, <first argument>)
| super(type) -> unbound super object
| super(type, obj) -> bound super object; requires isinstance(obj, type)
| super(type, type2) -> bound super object; requires issubclass(type2, type)
| Typical use to call a cooperative superclass method:
| class C(B):
| def meth(self, arg):
| super().meth(arg)
| This works for class methods too:
| class C(B):
| @classmethod
| def cmeth(cls, arg):
| super().cmeth(arg)
... ...
3 典型用法
3.1 单继承问题
首先我们看一个最基本的子类调用父类方法的示例:
>>> class A:
def funxx(self):
print("执行 A 中的 funxx 方法 ... ...")
>>> class B(A):
def funxx(self):
A.funxx(self) # 通过类名调用父类中的同名方法,self 参数代表 B 类的实例对象 b
print("执行 B 中的 funxx 方法 ... ...")
>>> b = B()
>>> b.funxx()
执行 A 中的 funxx 方法 ... ...
执行 B 中的 funxx 方法 ... ...
使用 super() 函数来实现父类方法的调用:
>>> class A:
def funxx(self):
print("执行 A 中的 funxx 方法 ... ...")
>>> class B(A):
def funxx(self):
super().funxx()
print("执行 B 中的 funxx 方法 ... ...")
>>> b = B()
>>> b.funxx()
执行 A 中的 funxx 方法 ... ...
执行 B 中的 funxx 方法 ... ...
3.2 单继承问题拓展
在 help()
的帮助信息中,也说明了类中使用 super()
不带参数的形式等同于 super(__class__, <first argument>)
这种形式。这也是 Python 2.x 和 Python 3.x 关于 super()
的区别。
改写之前的单继承问题的代码:
>>> class A:
def funxx(self):
print("执行 A 中的 funxx 方法 ... ...")
>>> class B(A):
def funxx(self):
super(B, self).funxx()
print("执行 B 中的 funxx 方法 ... ...")
>>> b = B()
>>> b.funxx()
执行 A 中的 funxx 方法 ... ...
执行 B 中的 funxx 方法 ... ...
A.funxx(self)
,其中 self 指代实例对象 b。用语言描述为:实例对象 b 通过 A 类名调用方法 funxx()
。super(B, self)
,第一个参数为 B,第二个参数 self 为实例 b,其所在类的继承顺序(MRO)为:B→A→object。所以调用时是在 B 的父类 A 中寻找,如找不到目标方法则会在更上一层的 object 中寻找。
示例:
class A:
pass
class B(A):
pass
class C(A):
def funxx(self):
print("找到 funxx() 位于 C 中...")
class D(A):
pass
class E(B, C):
pass
class F(E, D):
def funff(self):
print("执行 F 中的 funff()...")
super(E, self).funxx()
print(f"F 类的 MRO : {F.__mro__}")
f = F()
f.funff()
运行结果:
F 类的 MRO : (<class '__main__.F'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
执行 F 中的 funff()...
找到 funxx() 位于 C 中...
super()
函数的第一个参数为:E,目标是调用 E 类的父类 B 中的 funxx()
方法,可惜 B 类中没找到,在 B 类的兄弟类 C 中找到了,符合要求。
3.3 重复调用问题
重复调用问题 也称 钻石继承问题 或 菱形图问题。
先来看看普通调用方法在:
>>> class A:
def __init__(self):
print("打印属性 a")
>>> class B(A):
def __init__(self):
print("打印属性 b")
A.__init__(self)
>>> class C(A):
def __init__(self):
print("打印属性 c")
A.__init__(self)
>>> class D(B, C):
def __init__(self):
print("打印属性 d")
B.__init__(self)
C.__init__(self)
>>> d = D()
打印属性 d
打印属性 b
打印属性 a
打印属性 c
打印属性 a
接下来我们使用 super() 函数来调用:
>>> class A:
def __init__(self):
print("打印属性 a")
>>> class B(A):
def __init__(self):
print("打印属性 b")
super().__init__() # super() 等同于 super(B, self)
>>> class C(A):
def __init__(self):
print("打印属性 c")
super().__init__() # super() 等同于 super(C, self)
>>> class D(B, C):
def __init__(self):
print("打印属性 d")
super(D, self).__init__()
>>> d = D()
打印属性 d
打印属性 b
打印属性 c
打印属性 a
__init__()
方法,接着调用 B 类的 __init__()
方法,B 类的构造方法中又调用了父类 A 的 __init_()
方法,然后再是调用 C 类的 __init_()
方法,该方法也调用了父类 A 的 __init__()
方法。所以执行的结果应该是:打印属性 d,打印属性 b,打印属性 a,打印属性 c。super()
函数产生的是 d 的代理对象,当其调用父类 B 的 __init__()
时,B 的 super()
的第二个参数为 D 中的 super object,其所提供的 MRO 依旧为:D→B→C→A→object。也就是说 B 中的 super()
调用的是它的上一级 C 中的 __init__()
,而不是 A 中的 __init__()
。所以执行的结果是:打印属性 d,打印属性 b,打印属性 c,打印属性 a。
3.4 super(type) 问题
>>> class A:
def funxx(self):
print("...A...")
>>> class B(A):
def funxx(self):
print("...B...")
>>> sa = super(B)
>>> print(sa)
<super: <class 'B'>, NULL>
>>> print(type(sa))
<class 'super'>
来源:小皇鱼