python继承中子类访问父类的方法(包括__init__)主要有两种方法,一种是调用父类的未绑定方法,另一种是使用super(仅仅对于新式类),看下面的两个例子:
#coding:utf-8 class Father(object): #继承自object,使用新式类 def hello(self, name): print 'i am ' + name + ' from Father ' class Son(Father): def hello(self, name): print 'i am ' + name + ' from Son' Father.hello(self, name) # 使用父类的未绑定方法 super(Son, self).hello(name) #使用super来调用 s = Son() s.hello('zhangsan')
对于super的使用其实牵扯到一个MRO的问题,尤其在多重继承的时候尤为重要。先看一个最简单的多继承的例子:
#coding:utf-8 class A(object): def __init__(self): print '>> A' class B(object): def __init__(self): print '>> B' class C(A, B): def __init__(self): super(C, self).__init__() print '>> C' C()
结果为:
>> A
>> C
我们发现并没有访问到B的__init__方法。
C.mro() 返回 [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>] ( C --> A --> B --> object) , 当我们使用super时就是按照这个顺序来执行方法,
super(C, self).__init__()其实执行的是A的__init__方法,如果我们希望继续执行B的__init__方法,那么就必须在A的__init__方法中添加super调用,如果继承体系更加复杂,以此类推。 现在我们在A中加入super方法。
#coding:utf-8 class A(object): def __init__(self): super(A, self).__init__() #在A中新加入super方法 print '>> A' class B(object): def __init__(self): print '>> B' class C(A, B): def __init__(self): super(C, self).__init__() print '>> C' C()
执行的结果就是:
>> B
>> A
>> C
如果我们把C(A,B)改为C(B, A),也就是改变C的继承顺序,那么C的mro顺序就是( C --> B --> A --> object), 在C中的super会调用B, B中的super会调用A, 所以我们要希望同时调用A B的__init__就必须再在B中加入super调用,此时A中的super可有可无,它其实是调用object的__init__。
#coding:utf-8 class A(object): def __init__(self): #super(A, self).__init__() #在A中不再需要super print '>> A' class B(object): def __init__(self): super(B, self).__init__() #在B中加入super调用 print '>> B' class C(B, A): #改变C的继承顺序为 B, A def __init__(self): super(C, self).__init__() print '>> C' C()
结果为:
>> A
>> B
>> C
总结一下: 使用super时,是按照MRO顺序来寻找调用的是继承体系中的哪个方法。
上面的例子是构造方法,看下面的普通方法的使用:
#coding:utf-8 class A(object): def hello(self): super(A, self).hello() print '>> A' class B(object): def hello(self): print '>> B' class C(A, B): def hello(self): super(C, self).hello() print '>> C' c = C() c.hello() ''' >> B >> A >> C ''' a = A() a.hello() #AttributeError: 'super' object has no attribute 'hello'
上面的例子中,我希望在C中hello方法中同时调用A B的hello方法,c.hello()这样调用的确是可行的,会依次调用C -》 A -》 B的hello方法, 但是在A的hello方法中使用super是有隐患的,在A的实例上直接调用hello就会报错,因为此时是去调用object的hello方法,而object没有hello方法。
而且在多重继承中使用super时,如果传递参数也会很别扭:
#coding:utf-8 class A(object): def __init__(self, name): super(A, self).__init__(11) # 希望初始化B, 就必须在A 中传递具体参数,很显然不可取 self.name = name class B(object): def __init__(self, age): self.age = age class C(A, B): def __init__(self): super(C, self).__init__('zhangsan') #在C中只能够初始化A c = C() print c.name, c.age
在上面的例子中, C的父类A需要初始化name属性,父类B需要初始化age属性,在C中使用super仅仅能够初始化A中的name,对B没法处理,必须在A中去初始化B的age属性,这很明显是不可取得。
上面提到的这些问题,在单继承中都是不存在的。
我对python的多继承理解的并不深入,这篇文章主要说明了多继承中使用super的一些问题,其实我觉得还是尽量少用多继承为好。