I'm running Python 2.5, so this question may not apply to Python 3. When you make a diamond class hierarchy using multiple inheritance and create an object of the derived-most class, Python does the Right Thing (TM). It calls the constructor for the derived-most class, then its parent classes as listed from left to right, then the grandparent. I'm familiar with Python's MRO; that's not my question. I'm curious how the object returned from super actually manages to communicate to calls of super in the parent classes the correct order. Consider this example code:
#!/usr/bin/python class A(object): def __init__(self): print "A init" class B(A): def __init__(self): print "B init" super(B, self).__init__() class C(A): def __init__(self): print "C init" super(C, self).__init__() class D(B, C): def __init__(self): print "D init" super(D, self).__init__() x = D()
The code does the intuitive thing, it prints:
D init B init C init A init
However, if you comment out the call to super in B's init function, neither A nor C's init function is called. This means B's call to super is somehow aware of C's existence in the overall class hierarchy. I know that super returns a proxy object with an overloaded get operator, but how does the object returned by super in D's init definition communicate the existence of C to the object returned by super in B's init definition? Is the information that subsequent calls of super use stored on the object itself? If so, why isn't super instead self.super?
Edit: Jekke quite rightly pointed out that it's not self.super because super is an attribute of the class, not an instance of the class. Conceptually this makes sense, but in practice super isn't an attribute of the class either! You can test this in the interpreter by making two classes A and B, where B inherits from A, and calling dir(B)
. It has no super
or __super__
attributes.
An Overview of Python's super() Function While the official documentation is fairly technical, at a high level super() gives you access to methods in a superclass from the subclass that inherits from it. super() alone returns a temporary object of the superclass that then allows you to call that superclass's methods.
The super keyword refers to superclass (parent) objects. It is used to call superclass methods, and to access the superclass constructor. The most common use of the super keyword is to eliminate the confusion between superclasses and subclasses that have methods with the same name.
Use of super() Allows us to avoid using the base class name explicitly. Working with Multiple Inheritance.
In general it is necessary. And it's often necessary for it to be the first call in your init. It first calls the init function of the parent class ( dict ).
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 -
__mro__
attribute, that stores the method resolution order of that particular instance.__init__
) in the classes in the MRO, after the class specified as the first argument (in this case classes after DC). Explanation for your example
MRO: D,B,C,A,object
super(D, self).__init__()
is called. isinstance(self, D) => True Search for next method in the MRO in classes to the right of D.
B.__init__
found and called
B.__init__
calls super(B, self).__init__()
.
isinstance(self, B) => False
isinstance(self, D) => True
Thus, 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.
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