Python编程中对super函数的正确理解和用法解析
当在子类需要调用父类的方法时,在python2.2之前,直接用类名调用类的方法,即非绑定的类方法,并把自身对象self作参数传进去。
classA(object): defsay(self): print'IamA' classB(A): defsay(self): print'IamB' A.say(self) b=B() b.say()
输出
IamB IamA
这样运作挺好,不过有个问题,当父类改了名字时,就要把这些显式调用父类的一个个更正,子类和父类耦合比较高。
于是python2.2后就推出了super()函数来避免硬编码,不用关心父类名叫什么。
使用super()函数,上面的代码可以写成如下。
classB(A): defsay(self): print'IamB' super(B,self).say()
python3.0后,又做了改良,super()函数不用传参数,即上面的那行代码直接super().say()就行了。
需要注意的问题:
- super只能用在新式类中。
- super在多重继承有问题,如果子类继承多个父类,那么super调用第一个父类的方法。
- 不要混用这两种调用父类方法的方案,要么都用非绑定的类方法,要么都用super。不然可能导致没被调用或者被调用多次。
BUT:
不要一说到super就想到父类!super指的是MRO中的下一个类!
一说到super就想到父类这是初学者很容易犯的一个错误,也是我当年犯的错误。
defsuper(cls,inst): mro=inst.__class__.mro() returnmro[mro.index(cls)+1]
两个参数cls和inst分别做了两件事:
1.inst负责生成MRO的list
2.通过cls定位当前MRO中的index,并返回mro[index+1]
这两件事才是super的实质,一定要记住!
MRO全称MethodResolutionOrder,它代表了类继承的顺序。
举个例子:
classRoot(object): def__init__(self): print("thisisRoot") classB(Root): def__init__(self): print("enterB") #print(self)#thiswillprint<__main__.Dobjectat0x...> super(B,self).__init__() print("leaveB") classC(Root): def__init__(self): print("enterC") super(C,self).__init__() print("leaveC") classD(B,C): pass d=D() print(d.__class__.__mro__)
输出
enterB enterC thisisRoot leaveC leaveB (<class'__main__.D'>,<class'__main__.B'>,<class'__main__.C'>,<class'__main__.Root'>,<type'object'>)
知道了super和父类其实没有实质关联之后,我们就不难理解为什么enterB下一句是enterC而不是thisisRoot(如果认为super代表“调用父类的方法”,会想当然的认为下一句应该是thisisRoot)。流程如下,在B的__init__函数中:
super(B,self).__init__()
首先,我们获取self.__class__.__mro__,注意这里的self是D的instance而不是B的
(<class'__main__.D'>,<class'__main__.B'>,<class'__main__.C'>,<class'__main__.Root'>,<type'object'>)
然后,通过B来定位MRO中的index,并找到下一个。显然B的下一个是C。于是,我们调用C的__init__,打出enterC。顺便说一句为什么B的__init__会被调用:因为D没有定义__init__,所以会在MRO中找下一个类,去查看它有没有定义__init__,也就是去调用B的__init__。
其实这一切逻辑还是很清晰的,关键是理解super到底做了什么。