super的入门使用:
在类的继承中,如果定义某个方法,该方法会覆盖父类的同名方法,但有时候我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可以通过使用super来实现。比如:
class Animal(object): def __init__(self, name): self.name = name def greet(self): print(self.name) class Dog(Animal): def greet(self): super(Dog, self).greet() print('wang wang') obj = Dog('藏獒') obj.greet()
在上面代码中,Animal是父类,Dog是子类,我们在Dog类定义了greet方法,为了能同时实现父类的功能,我们又调用了父类的方法。
super的一个最常见用法可以说是在子类中调用父类的初始化方法了。
深入super:
以上的使用很简单,无非是获取了父类,并调用父类的方法。其实,在上面的情况下,super获得的类刚好是父类,但在其他情况就不一定了,super其实和父类没有实质性的关联。
首先看一个复杂点的例子,涉及多继承:
class Base(object): def __init__(self): print('enter base') print('leave base') class A(Base): def __init__(self): print('enter A') super(A, self).__init__() print('leave A') class B(Base): def __init__(self): print('enter B') super(B, self).__init__() print('leave B') class C(A, B): def __init__(self): print('enter C') super(C, self).__init__() print('leave C') obj = C()
其中,Base是父类,A、B继承Base,C继承A和B,执行结果如下:
enter C
enter A
enter B
enter base
leave base
leave B
leave A
leave C
如果你认为super代表调用父类的方法,那么你很可能疑惑为什么enterA的下一句不是enterBase而是enterB。原因是,super和父类没有实质性的关联,那么super是怎么运作的呢?
首先看一下MRO表吧:
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>)
mro表是通过一个C3线性化算法来实现的,遵循三条原则:
1、子类永远在父类前面
2、如果有多个父类,会根据他们在列表中的顺序被检查
3、如果对下一个类存在两个合法的选择,选择第一个父类
super原理:
def super(cls, inst): mro = inst.__class__.mro() return mro[mro.index(cls) + 1]
其中,cls代表类,inst代表实例,上面的代码做了两件事:
1、获取inst的mro列表
2、查找cls在当前mro列表中的index,并返回它的下一个类,即mro[index+1]
当你使用super(cls, inst)时,python会在inst的mro列表中搜索下一个类
现在,再回到上个示例:
首先看C的__init__方法:
整个过程还是比较清晰的,关键是要理解super的工作方式,而不是想当然地认为super调用了父类的方法。
小结:
事实上,super和父类没有实质性的关联
super(cls,inst)获得的是cls在inst的mro列表中的下一个类。