Python super调用父类的非__init__函数

先看如下一段代码:

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.onTimer()

输出为:

1
2
3
4
''' 
'''

代码是多重继承,希望调到所有的基类的同名函数,但是从输出来看,只有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文档说明如下:

PyObjectPyTypeObject.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.onTimer() 
           
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、B、C都调到了。

但是,A类明显存在问题的:

1
2
3
4
5
6
如果直接使用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.onTimer() 
      
输出: 
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  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  in  self.obj.__class__.__mro__: 
             if  not start: 
                 if  is  self.curType: 
                     start = True 
             else
                 f = getattr(b, name, None) 
                 if  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  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  in  self.obj.__class__.__mro__: 
             if  not start: 
                 if  is  self.curType: 
                     start = True 
             else
                 f = getattr(b, name, None) 
                 if  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()

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值