问题
I am little confused about python multiple inheritance.
For example if you had:
class A(object):
def __init__(self):
print "init A"
super(A, self).__init__()
class B(A):
def __init__(self):
print "init B"
super(B, self).__init__()
class C(A):
def __init__(self):
print "init C"
super(C, self).__init__()
class D(C, B):
def __init__(self):
print "init D"
super(D, self).__init__()
if __name__ == '__main__':
D()
The method resolution order (MRO) would be D-C-B-A.
Why the order is not D-C-A-B-A?
回答1:
Python docs:
With new-style classes, dynamic ordering is necessary because all cases of multiple inheritance exhibit one or more diamond relationships (where at least one of the parent classes can be accessed through multiple paths from the bottommost class). For example, all new-style classes inherit from object, so any case of multiple inheritance provides more than one path to reach object. To keep the base classes from being accessed more than once, the dynamic algorithm linearizes the search order in a way that preserves the left-to-right ordering specified in each class, that calls each parent only once, and that is monotonic (meaning that a class can be subclassed without affecting the precedence order of its parents). Taken together, these properties make it possible to design reliable and extensible classes with multiple inheritance. For more detail, see https://www.python.org/download/releases/2.3/mro/.
回答2:
Roughly speaking, the MRO is given by taking all of the bases going depth-first, left to right, and then removing any duplicates, simply leaving the last.
The algorithm is such that for any of the base classes, the order of its base classes in the mro will always be the same (if this is not possible I believe you get an error).
If duplicates were not removed, the order would actually be D-C-A-object-B-A-object. This is confusing for a number of reasons. Firstly, if methods call super, as in your case, then the same method can be called twice. Secondly, it is reasonable for the implementation of B to expect to be ahead of A and object in the method resolution order. If it overrides properties of A, it is not expected that this overriding will be reversed.
回答3:
The reason the MRO is D-C-B-A is that, it being D-C-A-B-A (or D-C-A-B) would have strange effects. In this particular example, the A
class constructor takes no arguments and explicitly does the super()
call that only matters in diamond inheritance trees. If it didn't do the super
call, then the B
constructor wouldn't be called from the A
constructor. If the constructors took arguments then the A
constructor would be stuck between a rock and a hard place. If it didn't call super
then it wouldn't work in diamond inheritances. If it did call super
then, since object.__init__
takes no arguments, the constructor would fail if it wasn't used in a diamond inheritance pattern.
回答4:
You instantiate only one object. Python allows each ancestor's __init__
to execute only once in the MRO. Thus, we don't get both the A->C and A->B relationships executing A.__init__
With only that much explained, you might think we'd get D-C-A-B ... but since B also requires A.__init__
, the MRO is patient enough to resolve the entire graph before determining the execution order.
来源:https://stackoverflow.com/questions/33222068/python-multiple-inheritance-super-function