How does Python's "super" do the right thing?
Change your code to this and I think it'll explain things (presumably super
is looking at where, say, B
is in the __mro__
?):
class A(object): def __init__(self): print "A init" print self.__class__.__mro__class B(A): def __init__(self): print "B init" print self.__class__.__mro__ super(B, self).__init__()class C(A): def __init__(self): print "C init" print self.__class__.__mro__ super(C, self).__init__()class D(B, C): def __init__(self): print "D init" print self.__class__.__mro__ super(D, self).__init__()x = D()
If you run it you'll see:
D init(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)B init(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)C init(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)A init(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
Also it's worth checking out Python's Super is nifty, but you can't use it.
I have provided a bunch of links below, that answer your question in more detail and more precisely than I can ever hope to. I will however give an answer to your question in my own words as well, to save you some time. I'll put it in points -
- super is a builtin function, not an attribute.
- Every type (class) in Python has an
__mro__
attribute, that stores the method resolution order of that particular instance. - Each call to super is of the form super(type[, object-or-type]). Let us assume that the second attribute is an object for the moment.
- At the starting point of super calls, the object is of the type of the Derived class (say DC).
- super looks for methods that match (in your case
__init__
) in the classes in the MRO, after the class specified as the first argument (in this case classes after DC). - When the matching method is found (say in class BC1), it is called.
(This method should use super, so I am assuming it does - See Python's super is nifty but can't be used - link below)That method then causes a search in the object's class' MRO for the next method, to the right of BC1. - Rinse wash repeat till all methods are found and called.
Explanation for your example
MRO: D,B,C,A,object
super(D, self).__init__()
is called. isinstance(self, D) => TrueSearch for next method in the MRO in classes to the right of D.
B.__init__
found and called
B.__init__
callssuper(B, self).__init__()
.isinstance(self, B) => False
isinstance(self, D) => TrueThus, the MRO is the same, but the search continues to the right of B i.e. C,A,object are searched one by one. The next
__init__
found is called.And so on and so forth.
An explanation of super
http://www.python.org/download/releases/2.2.3/descrintro/#cooperation
Things to watch for when using super
http://fuhm.net/super-harmful/
Pythons MRO Algorithm:
http://www.python.org/download/releases/2.3/mro/
super's docs:
http://docs.python.org/library/functions.html
The bottom of this page has a nice section on super:
http://docstore.mik.ua/orelly/other/python/0596001886_pythonian-chp-5-sect-2.html
I hope this helps clear it up.
just guessing:
self
in all the four methods refer to the same object, that is, of class D
.so, in B.__init__()
, the call to to super(B,self)
knows the whole diamond ancestry of self
and it has to fetch the method from 'after' B
. in this case, it's the C
class.