先看如下一段代码:
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() |