Python - 对多继承以及super的一些了解
2015-03-01 18:37
357 查看
Python支持多继承,与C++一样都会出现一种问题:子类继承的多个父类又继承了同一个父类,这时就有可能会出现父类构造方法被调用多次的情况。关于这个问题,我找了一些资料,虽然没有亲自全部验证,这里我总结一下自己对这个问题的看法。
Python和C++的关于这个问题的解决方案不太一样,当然Python还要看它的版本。
C++用的方案是引入了虚继承的语法避免同一个类被构造了多次。
Python用的方法是MRO(method resolution order,方法解析顺序) 。在在Python2.3之前,MRO的实现是基于DFS的,而在Python2.3以后MRO的实现是基于C3算法。找到的资料解释了一下更换算法的原因:
为什么采用C3算法
C3算法最早被提出是用于Lisp的,应用在Python中是为了解决原来基于深度优先搜索算法不满足本地优先级,和单调性的问题。
本地优先级:指声明时父类的顺序,比如C(A,B),如果访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类。
单调性:如果在C的解析顺序中,A排在B的前面,那么在C的所有子类里,也必须满足这个顺序。
------------------------------新式类和旧式类中查找属性的顺序不同-------------------------------------
在新式类中,查找一个要调用的函数或者属性的时候,是广度优先搜搜的。
在旧式类当中,是深度优先搜索的。如下图所示:
![](http://img.my.csdn.net/uploads/201303/29/1364559227_2271.jpg)
来一个例子:
例子中定义D类的时候,D是新式类,所以D的所有子类都是新式类。
A的实例对象f在调用foo函数的时候,根据广度优先搜索原则,调用的是C类里面的foo函数。
上面的代码输出class C
如果定义D类的时候直接class D,而不是class D(object),那么上述代码就该输出class D了。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
如果我用的是super来解决多继承的初始化问题的话,那么到底是怎么初始化的呢?
这是我一开始想到的一个问题:
第十一行的那个'?'的位置到底是填是什么进去才对呢?
我一开始认为因为是多继承多以需要初始化父类的时候A,B都需要初始化,那么问题来了,super(C,self).__init__(?)怎么写?
我试了一下:
① ? = 1 --> 输出1
② ? = 1,2 --> TypeError: __init__() takes exactly 2 arguments (3 given)
定义C的时候改成class(B,A)
③ ? = 1 --> TypeError: __init__() takes exactly 3 arguments (2 given)
④ ? =1,2 --> 输出3
再来看另一段代码:
说明什么问题?在调用super(classname,self).__init__()的时候应该调用在继承的父类列表里面有实现__init__()这个方法而且最靠左边的那个父类的构造方法,而且这个__init__(?)的'?'一定要与父类列表的里面第一个有构造方法的父类的构造方法签名一样才可以。
所以如果需要对所有父类都进行一遍初始化,还是使用类通过类名调用未绑定的初始化方法好(我说这一句话是因为我还不是很了解super)。
说一下super的使用:
super( classname,对象(一般情况是self) ) 返回的是一个super对象,你可以把它当作父类列表里面有实现__init__()这个方法而且最靠左边的那个父类的一个对象就可以了。
参考文章地址:
http://blog.csdn.net/imzoer/article/details/8737642
http://blog.csdn.net/zyflying/article/details/8636006
Python和C++的关于这个问题的解决方案不太一样,当然Python还要看它的版本。
C++用的方案是引入了虚继承的语法避免同一个类被构造了多次。
Python用的方法是MRO(method resolution order,方法解析顺序) 。在在Python2.3之前,MRO的实现是基于DFS的,而在Python2.3以后MRO的实现是基于C3算法。找到的资料解释了一下更换算法的原因:
为什么采用C3算法
C3算法最早被提出是用于Lisp的,应用在Python中是为了解决原来基于深度优先搜索算法不满足本地优先级,和单调性的问题。
本地优先级:指声明时父类的顺序,比如C(A,B),如果访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类。
单调性:如果在C的解析顺序中,A排在B的前面,那么在C的所有子类里,也必须满足这个顺序。
------------------------------新式类和旧式类中查找属性的顺序不同-------------------------------------
在新式类中,查找一个要调用的函数或者属性的时候,是广度优先搜搜的。
在旧式类当中,是深度优先搜索的。如下图所示:
![](http://img.my.csdn.net/uploads/201303/29/1364559227_2271.jpg)
来一个例子:
# -*- coding:utf-8 -*- class D(object): def foo(self): print "class D" class B(D): pass class C(D): def foo(self): print "class C" class A(B, C): pass f = A() f.foo()
例子中定义D类的时候,D是新式类,所以D的所有子类都是新式类。
A的实例对象f在调用foo函数的时候,根据广度优先搜索原则,调用的是C类里面的foo函数。
上面的代码输出class C
如果定义D类的时候直接class D,而不是class D(object),那么上述代码就该输出class D了。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
如果我用的是super来解决多继承的初始化问题的话,那么到底是怎么初始化的呢?
这是我一开始想到的一个问题:
class A(object): def __init__(self,a): print a class B(object): def __init__(self,a,b): print a+b class C(A,B): def __init__(self): super(C,self).__init__(?) obj = C()
第十一行的那个'?'的位置到底是填是什么进去才对呢?
我一开始认为因为是多继承多以需要初始化父类的时候A,B都需要初始化,那么问题来了,super(C,self).__init__(?)怎么写?
我试了一下:
① ? = 1 --> 输出1
② ? = 1,2 --> TypeError: __init__() takes exactly 2 arguments (3 given)
定义C的时候改成class(B,A)
③ ? = 1 --> TypeError: __init__() takes exactly 3 arguments (2 given)
④ ? =1,2 --> 输出3
再来看另一段代码:
class A(object): def func(self): print 1 class B(object): def __init__(self): print 2 class C(A,B): def __init__(self): super(C,self).__init__() obj = C() #The output is 3
说明什么问题?在调用super(classname,self).__init__()的时候应该调用在继承的父类列表里面有实现__init__()这个方法而且最靠左边的那个父类的构造方法,而且这个__init__(?)的'?'一定要与父类列表的里面第一个有构造方法的父类的构造方法签名一样才可以。
所以如果需要对所有父类都进行一遍初始化,还是使用类通过类名调用未绑定的初始化方法好(我说这一句话是因为我还不是很了解super)。
说一下super的使用:
super( classname,对象(一般情况是self) ) 返回的是一个super对象,你可以把它当作父类列表里面有实现__init__()这个方法而且最靠左边的那个父类的一个对象就可以了。
参考文章地址:
http://blog.csdn.net/imzoer/article/details/8737642
http://blog.csdn.net/zyflying/article/details/8636006
相关文章推荐
- Python的继承以及调用父类成员:super用法
- java构造函数是否可继承,以及子类构造函数可否不使用super调用超类构造函数
- python中对象以及一些函数的应用
- JS 中的call 和 apply ,以及实现继承的一些研究
- Python 类继承,__bases__, __mro__, super
- Python 类继承,__bases__, __mro__, super
- python2.6使用mysql包出现的一些问题以及解决办法
- python普通继承和super继承
- webpy,希望能多了解一些关于WSGI,PYTHON的WEB开发框架的事,也希望能进一步了解PYTHON
- EF里的继承映射关系TPH、TPT和TPC的讲解以及一些具体的例子
- Python 类继承,__bases__, __mro__, super
- python 继承中的一个super使用
- Python 2.7不能使用super继承tk的问题
- python dict 字典 以及 赋值 引用的一些小实验
- python httplib2 超时以及一些问题
- python2.6使用mysql包出现的一些问题以及解决办法
- Python之道–实例和类的继承以及运算符重载
- EF里的继承映射关系TPH、TPT和TPC的讲解以及一些具体的例子
- python继承中super的问题
- 关于python的继承,super关键字