2015-11-10 90 views
2

为什么用super()调用父类不工作,而使用'直接'调用工作正常吗?Python的继承和超()

class A(object): 
    def __init__(self, x): 
     self.x = x 
     print("Inside A __init__. x = %s" % self.x) 
class B(object): 
    def __init__(self, y): 
     self.y = y 
     print("Inside B __init__. y = %s" % self.y) 
class C(A,B): 
    def __init__(self, z): 
     super(C, self).__init__(6) 
     super(C, self).__init__(5) 
     #1. A.__init__(self,6) 
     #2. B.__init__(self,5) 
     self.z = z 
     print("Inside C __init__. z = %s" % self.z) 
if __name__ == "__main__": 
    log = C(2) 

随着注释掉 '超级' 我得到的结果是:

Inside A __init__. x = 6 
Inside A __init__. x = 5 
Inside C __init__. z = 2 

所以对 'B' 初始化类的代码不会被调用。但是,使用注释行“#1”和“2号”后的代码工作,因为它应该:

Inside A __init__. x = 6 
Inside B __init__. y = 5 
Inside C __init__. z = 2 

问题:

  1. 这是什么奇怪的原因“超级()”行为。
  2. 可以super()在'B'中调用init
  3. 是否有任何其他方式调用所有'初始的父类?
+0

它的经典之作:“Raymond Hettinger--超级超级!”,https://www.youtube.com/watch?v=EiOglTERPEo – sobolevn

+0

TL; DR:“超级”不是用于访问特定父类。它的使用必须在所有涉及的类中进行协调。 – chepner

+0

对于那些不喜欢视频的人来说,以下是原始素材:https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ – chepner

回答

3

一个答案,这更应被视为一个如何super的作品,而不是如何实际编写代码:

class A(object): 
    def __init__(self, x): 
     self.x = x 
     print("Inside A __init__. x = %s" % self.x) 
class B(object): 
    def __init__(self, y): 
     self.y = y 
     print("Inside B __init__. y = %s" % self.y) 
class C(A,B): 
    def __init__(self, z): 
     super(C, self).__init__(6) 
     super(A, self).__init__(5) 
     self.z = z 
     print("Inside C __init__. z = %s" % self.z) 
if __name__ == "__main__": 
    log = C(2) 

每个类都有一个方法解析顺序(MRO),这是在查找继承的函数时使用。为C,该顺序是

>>> C.__mro__ 
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>) 

super(foo, bar)提供到(实际上是一个用于代理)中的type(bar)的MRO foo之后的下一个类的引用。 super(C, self)A提供了一个参考(真的是代理),因此A.__init__是最终的调用。但是,super(A, self)提供了B的代理,导致致电B.__init__

通用的规则,不过,是你真的不知道什么方法接下来将调用,因为你不必知道的self类型(它可能是一个派生类的一个实例一与C的实例不同的MRO)。要正确使用super,您需要确保所有潜在类正在使用它,以便始终正确调度方法。

+0

您可以为每个示例添加'mro()' ,我想这可能会有帮助。 – sobolevn