python 多继承(新式类) 三
2013-08-26 22:22
369 查看
深入super
一下内容引用自:/article/6540351.html,写的挺好的。
f=F(),结果如下:
明显地,类A和类D的初始化函数被重复调用了2次,这并不是我们所期望的结果!我们所期望的结果是最多只有类A的初始化函数被调用2次——其实这是多继承的类体系必须面对的问题。我们把代码段4的类体系画出来,如下图:
object
|\
|A
|/|
BCD
\/|
E|
\|
F
按我们对super的理解,从图中可以看出,在调用类C的初始化函数时,应该是调用类A的初始化函数,但事实上却调用了类D的初始化函数。好一个诡异的问题!
也就是说,mro中记录了一个类的所有基类的类类型序列。查看mro的记录,发觉包含7个元素,7个类名分别为:
FEBCDAobject
从而说明了为什么在C.__init__中使用super(C,self).__init__()会调用类D的初始化函数了。???
我们把代码段4改写为:
f=F(),执行结果:
小结
1.super并不是一个函数,是一个类名,形如super(B,self)事实上调用了super类的初始化函数,
产生了一个super对象;
2.super类的初始化函数并没有做什么特殊的操作,只是简单记录了类类型和具体实例;
3.super(B,self).func的调用并不是用于调用当前类的父类的func函数;
4.Python的多继承类是通过mro的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数
只调用一次(如果每个类都使用super);
5.混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一
个父类函数被调用多次。
一些更深入的问题:各位可以看到,printF.__mro__时发现里面元素的顺序是FEBCDAobject,这就是F的基类查找顺序,至于为什么是这样的顺序,以及python内置的多继承顺序是怎么实现的,这涉及到mro顺序的实现,python2.3以后的版本中是采用的一个叫做C3的算法,在下篇博客中进行介绍。
一下内容引用自:
代码段3
classA(object):#Amustbenew-styleclass def__init__(self): print"enterA" print"leaveA" classB(C):#A-->C def__init__(self): print"enterB" super(B,self).__init__() print"leaveB"
在我们的印象中,对于super(B,self).__init__()是这样理解的:super(B,self)首先找到B的父类(就是类A),然后把类B的对象self转换为类A的对象,然后“被转换”的类A对象调用自己的__init__函数。 有一天某同事设计了一个相对复杂的类体系结构(我们先不要管这个类体系设计得是否合理,仅把这个例子作为一个题目来研究就好),代码如下 代码段4:
classA(object): def__init__(self): print"enterA" print"leaveA" classB(object): def__init__(self): print"enterB" print"leaveB" classC(A): def__init__(self): print"enterC" super(C,self).__init__() print"leaveC" classD(A): def__init__(self): print"enterD" super(D,self).__init__() print"leaveD" classE(B,C): def__init__(self): print"enterE" B.__init__(self) C.__init__(self) print"leaveE" classF(E,D): def__init__(self): print"enterF" E.__init__(self) D.__init__(self) print"leaveF"
f=F(),结果如下:
enterF enterE enterB leaveB enterC enterD enterA leaveA leaveD leaveC leaveE enterD enterA leaveA leaveD leaveF
明显地,类A和类D的初始化函数被重复调用了2次,这并不是我们所期望的结果!我们所期望的结果是最多只有类A的初始化函数被调用2次——其实这是多继承的类体系必须面对的问题。我们把代码段4的类体系画出来,如下图:
object
|\
|A
|/|
BCD
\/|
E|
\|
F
按我们对super的理解,从图中可以看出,在调用类C的初始化函数时,应该是调用类A的初始化函数,但事实上却调用了类D的初始化函数。好一个诡异的问题!
也就是说,mro中记录了一个类的所有基类的类类型序列。查看mro的记录,发觉包含7个元素,7个类名分别为:
FEBCDAobject
从而说明了为什么在C.__init__中使用super(C,self).__init__()会调用类D的初始化函数了。???
我们把代码段4改写为:
代码段5:
classA(object): def__init__(self): print"enterA" super(A,self).__init__()#new print"leaveA" classB(object): def__init__(self): print"enterB" super(B,self).__init__()#new print"leaveB" classC(A): def__init__(self): print"enterC" super(C,self).__init__() print"leaveC" classD(A): def__init__(self): print"enterD" super(D,self).__init__() print"leaveD" classE(B,C): def__init__(self): print"enterE" super(E,self).__init__()#change print"leaveE" classF(E,D): def__init__(self): print"enterF" super(F,self).__init__()#change print"leaveF"
f=F(),执行结果:
enterF enterE enterB enterC enterD enterA leaveA leaveD leaveC leaveB leaveE leaveF 可见,F的初始化不仅完成了所有的父类的调用,而且保证了每一个父类的初始化函数只调用一次。
小结
1.super并不是一个函数,是一个类名,形如super(B,self)事实上调用了super类的初始化函数,
产生了一个super对象;
2.super类的初始化函数并没有做什么特殊的操作,只是简单记录了类类型和具体实例;
3.super(B,self).func的调用并不是用于调用当前类的父类的func函数;
4.Python的多继承类是通过mro的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数
只调用一次(如果每个类都使用super);
5.混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一
个父类函数被调用多次。
一些更深入的问题:各位可以看到,printF.__mro__时发现里面元素的顺序是FEBCDAobject,这就是F的基类查找顺序,至于为什么是这样的顺序,以及python内置的多继承顺序是怎么实现的,这涉及到mro顺序的实现,python2.3以后的版本中是采用的一个叫做C3的算法,在下篇博客中进行介绍。
相关文章推荐
- python多继承(新式类)一
- python中类继承和新式类的写法
- Python中新式类 经典类的区别(即类是否继承object)
- Python中新式类 经典类的区别(即类是否继承object)
- python多继承(新式类)一
- Python新式类继承的C3算法
- 关于 python 新式类和旧式类继承顺序的验证
- Python中新式类 经典类的区别(即类是否继承object)
- python 多继承(新式类) 二
- python多继承(新式类)一
- Python新式类多重继承时的顺序
- Python中新式类 经典类的区别(即类是否继承object)
- python新式类多重继承 广度优先搜索 C3算法
- python 多继承(新式类) 四
- python 零散记录(七)(下) 新式类 旧式类 多继承 mro 类属性 对象属性
- python 多继承(新式类) 三
- Python 多继承(新式类) 的mro算法
- python 多继承(新式类) 二
- python支持多重继承
- python常见的错误类型和继承关系