先看如下一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class
A(
object
):
def
onTimer(
self
):
print
"A"
class
B(
object
):
def
onTimer(
self
):
print
"B"
class
C(A, B):
def
onTimer(
self
):
super
(C,
self
).onTimer()
print
"C"
c
=
C()
c.onTimer()
|
输出为:
1
2
3
4
|
'''
A
C
'''
|
代码是多重继承,希望调到所有的基类的同名函数,但是从输出来看,只有A、C的调用了。
之前总结过 关于Python中的super以及调用父类构造函数[Python],对比上面的代码,在A和B中没有写super,但是也没法super了,因为A的父类是object,是没有onTimer函数的。
现在从Python源码来探究下super:
在工程中搜索super,会在 bltinmodule.c 中找到:
即super是Python的一种内置类型——PySuper_Type。
typeobject.c中PySuper_Type的定义:
其中包含superobject,在typeobject.c中superobject的定义:
其中包含3个指针。
再看PySuper_Type中指定的super_init:
代码中写 super(C, self) 的时候会做super_init操作,结合上面的代码,初步确定type就是前面的class C的类型,obj就是C的对象,obj_type就是C对象的类型。
如果是一个子类对象,那么type和obj_type是一致的,如果是一个父类中的super,那么type就是父类类型,obj_type还是具体子类的类型。
上面得到的super对象在调用onTimer的时候,会有一个super_getattro的逻辑,代码如下:
super_getattro的逻辑是:
先找到starttype,即具体子类的类型,上面就是C的实例c对应的类。
然后遍历starttype的mro,找到当前类型在mro中的位置,在找到的这个位置之后的那些类里面搜索要查找的名字(比如上面的onTimer)。
因此,可以确定super是通过最终子类的mro来确保继承体系上每个类里面的同名函数调用且只被调用一次的。
关于mro,Python文档说明如下:
PyObject* PyTypeObject.tp_mro
Tuple containing the expanded set of base types, starting with the type itself and ending with object, in Method Resolution Order.
This field is not inherited; it is calculated fresh by PyType_Ready().
了解了上面的一些细节,我们可以输出最开始那段代码各个类的mro来看看:
1
2
3
4
5
6
7
8
9
|
代码:
print
A.__mro__
print
B.__mro__
print
C.__mro__
结果如下:
(<
class
'__main__.A'
>, <
type
'object'
>)
(<
class
'__main__.B'
>, <
type
'object'
>)
(<
class
'__main__.C'
>, <
class
'__main__.A'
>, <
class
'__main__.B'
>, <
type
'object'
>)
|
在调用到A的onTimer之后,由于在A的onTimer中没有调用super的onTimer,调用链断掉。
按照上面的规则,我们可以试下这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
代码:
class
A(
object
):
def
onTimer(
self
):
print
"A"
super
(A,
self
).onTimer()
class
B(
object
):
def
onTimer(
self
):
print
"B"
class
C(A, B):
def
onTimer(
self
):
print
"C"
super
(C,
self
).onTimer()
c
=
C()
c.onTimer()
print
A.__mro__
print
B.__mro__
print
C.__mro__
输出:
C
A
B
(<
class
'__main__.A'
>, <
type
'object'
>)
(<
class
'__main__.B'
>, <
type
'object'
>)
(<
class
'__main__.C'
>, <
class
'__main__.A'
>, <
class
'__main__.B'
>, <
type
'object'
>)
|
这样,A、B、C都调到了。
但是,A类明显存在问题的:
1
2
3
4
5
6
|
如果直接使用A类:
a
=
A()
a.onTimer()
就会出现错误:
AttributeError:
'super'
object
has no attribute
'onTimer'
|
为了解决这个问题,我们可以增加一个包含onTimer的最终父类,在它里面不再调用父类的onTimer,然后所有需要实现onTimer的子类都存在一个到该最终父类的继承关系。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
代码:
class
T(
object
):
def
onTimer(
self
):
print
"T"
class
A(T):
def
onTimer(
self
):
print
"A"
super
(A,
self
).onTimer()
class
B(T):
pass
# def onTimer(self):
# print "B"
# super(B, self).onTimer()
class
C(T):
def
onTimer(
self
):
print
"C"
super
(C,
self
).onTimer()
class
F(
object
):
pass
class
G(F, T):
def
onTimer(
self
):
print
"G"
super
(G,
self
).onTimer()
class
D(A, B, C, G):
def
onTimer(
self
):
print
"D"
super
(D,
self
).onTimer()
class
E(D):
def
onTimer(
self
):
print
"E"
super
(E,
self
).onTimer()
e
=
E()
e.onTimer()
输出:
E
D
A
C
G
T
|
另外,朱斌用脚本实现的super:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
class
MySuperFunc(object):
def __init__(self,f,s):
super
(MySuperFunc,self).__init__()
self.f = f
self.s = s
def __call__(self,*params):
fp = [self.s]
for
p
in
params:
fp.append(p)
self.f(*fp)
class
MySuper(object):
def __init__(self,curType,obj):
super
(MySuper,self).__init__()
self.curType = curType
self.obj = obj
def __getattr__(self, name):
start = False
for
b
in
self.obj.__class__.__mro__:
if
not start:
if
b
is
self.curType:
start = True
else
:
f = getattr(b, name, None)
if
f
is
not None and callable(f):
return
MySuperFunc(f,self.obj)
class
MySuperFunc(object):
def __init__(self,f,s):
super
(MySuperFunc,self).__init__()
self.f = f
self.s = s
def __call__(self,*params):
fp = [self.s]
for
p
in
params:
fp.append(p)
self.f(*fp)
class
MySuper(object):
def __init__(self,curType,obj):
super
(MySuper,self).__init__()
self.curType = curType
self.obj = obj
def __getattr__(self, name):
start = False
for
b
in
self.obj.__class__.__mro__:
if
not start:
if
b
is
self.curType:
start = True
else
:
f = getattr(b, name, None)
if
f
is
not None and callable(f):
return
MySuperFunc(f,self.obj)
class
TimerObj(object):
def abc(self):
print
"T"
class
D(TimerObj):
def abc(self):
print
"D 1"
,self
MySuper(D,self).abc()
print
"D 2"
pass
class
A(D):
def abc(self):
print
"A 1"
,self
MySuper(A,self).abc()
print
"A 2"
pass
class
B(D):
def abc(self):
print
"B 1"
,self
MySuper(B,self).abc()
print
"B 2"
class
C(A,B):
def abc(self):
print
"C 1"
,self
MySuper(C,self).abc()
print
"C 2"
c = C()
c.abc()
|