在Python中混合超级和经典调用

时间:2010-09-17 13:10:40

标签: python

首先,让我引用一篇来自“专家Python编程”一书的文章:

  

在下面的示例中,将使用__init__方法调用其基类的C类   让B班被叫两次!

class A(object):
    def __init__(self):
        print "A"
        super(A, self).__init__()

class B(object):
    def __init__(self):
        print "B"
        super(B, self).__init__()

class C(A,B):
    def __init__(self):
        print "C"
        A.__init__(self)
        B.__init__(self)

print "MRO:", [x.__name__ for x in C.__mro__]  #prints MRO: ['C', 'A', 'B', 'object']
C()  #prints C A B B

最后,这里是对这里发生的事情的解释:

  

这是由于A .__ init __(self)调用发生的,这是使用C实例进行的,   从而使super(A,self).__ init __()调用B的构造函数。换句话说,   super应该用于整个类层次结构。问题是有时候   此层次结构的一部分位于第三方代码中。

我不知道为什么“super(A, self).__init__()调用B的构造函数”。请解释这一刻。非常感谢。

2 个答案:

答案 0 :(得分:9)

要理解此行为,您必须了解super调用不是基类,而是按照__mro__中的顺序搜索下一个匹配方法。因此,调用super(A, self).__init__()查看__mro__ == ['C', 'A', 'B', 'object'],将B视为具有匹配方法的下一个类,并调用B的方法(构造函数)。

如果您将C更改为

class C(A,B):
    def __init__(self):
        print "C1"
        A.__init__(self)
        print "C2"
        B.__init__(self)
        print "C3"

你得到了

MRO: ['C', 'A', 'B', 'object']
C1
A
B
C2
B
C3

显示A的构造函数如何调用B

答案 1 :(得分:4)

super的文档说:

  

返回一个代理对象,该方法将方法调用委托给父类或兄弟类类型。这对于访问已在类中重写的继承方法很有用。搜索顺序与getattr()使用的搜索顺序相同,只是跳过了类型本身。

当您从A.__init__(self)内执行C时,super(A, self)将返回<super: <class 'A'>, <C object>>。由于实例是C<C object>),所以C的继承层次结构中的所有类都被选中。所有人都发出__init__电话。因此,您会看到“B”被调用两次。

要验证这个,请添加另一个类'Z'并让'C'继承'Z'。走着瞧吧。

class Z(object):
    def __init__(self):
        print "Z"
        super(Z, self).__init__()

class C(A, B, Z):    
    def __init__(self):
        print "C"
        A.__init__(self)
        B.__init__(self)
        Z.__init__(self)

在这种情况下,A会调用BZB也会调用Z