firstly, let me quote a bit an essay from "Expert Python Programming" book:
In the following example, a C class that calls its base classes using the __init__ method will make B class be called twice!
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
and finally, here is an explanation of what's going on here:
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.
i have no idea why "super(A, self).__init__()
calls B's constructor". Please explain this moment. Thanks a lot.
To understand this behaviour, you have to understand that super
calls not the base class, but searches the next matching method along the order in the __mro__
. So, the call super(A, self).__init__()
looks at the __mro__ == ['C', 'A', 'B', 'object']
, sees B
as the next class with a matching method and calls the method (constructor) of B
.
If you change C
to
class C(A,B):
def __init__(self):
print "C1"
A.__init__(self)
print "C2"
B.__init__(self)
print "C3"
you get
MRO: ['C', 'A', 'B', 'object']
C1
A
B
C2
B
C3
which shows how the constructor of A
calls B
.
The documentation for super
says that:
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.
When you execute A.__init__(self)
from within C
the super(A, self)
will return <super: <class 'A'>, <C object>>
. As the instance is C
(<C object>
) all the classes in C's inheritance hierarchy are picked up. And the __init__
call is issued on all of them. Consequently you see 'B' getting called twice.
To verify this add another class 'Z' and let 'C' inherit from 'Z' as well. See what happens.
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)
In this case, A
will call B
and Z
. B
will call Z
as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With