在python中mixing super和经典调用

mixing super and classic calls in Python

首先,让我引用一下"Python编程专家"一书中的一篇文章:

In the following example, a C class that calls its base classes using the __init__ method will
make B class be called twice!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

最后,这里是一个关于这里发生了什么的解释:

This happens due to the A.__init__(self) call, which is made with the C instance,
thus making super(A, self).__init__() call B's constructor. In other words,
super should be used into the whole class hierarchy. The problem is that sometimes
a part of this hierarchy is located in third-party code.

我不知道为什么"super(A, self).__init__()调用B的构造函数"。请解释一下这个时刻。谢谢。


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

如果你把C改为

1
2
3
4
5
6
7
class C(A,B):
    def __init__(self):
        print"C1"
        A.__init__(self)
        print"C2"
        B.__init__(self)
        print"C3"

你得到

1
2
3
4
5
6
7
MRO: ['C', 'A', 'B', 'object']
C1
A
B
C2
B
C3

说明了A的构造函数如何调用B


super的文件表明:

Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped.

当你在C内执行A.__init__(self)时,super(A, self)将返回, >。由于实例是C(),C继承层次中的所有类都被提取。对所有人都发出了__init__号电话。结果你看到"B"被打了两次电话。

要验证这一点,请添加另一个类"z",并让"c"也从"z"继承。看看会发生什么。

1
2
3
4
5
6
7
8
9
10
11
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