Consider the following situation:
class A(object): def __init__(self): print('Running A.__init__') super(A,self).__init__() class B(A): def __init__(self): print('Running B.__init__')
So, classes form the so-called inheritance diamond:
A / \ BC \ / D
Running code gives
Running D.__init__ Running B.__init__ Running A.__init__
This is bad because C __init__ skipped. The reason for this is because B __init__ calls A __init__ directly.
The purpose of super is to allow diamonds of inheritance . If you do not comment
and comment
A.__init__(self)
the code gives a more desirable result:
Running D.__init__ Running B.__init__ Running C.__init__ Running A.__init__
Now all __init__ methods are called. Note that while you are defining B.__init__ , you might think that super(B,self).__init__() same as calling A.__init__(self) , but you are mistaken. In the situation above, super(B,self).__init__() actually calls C.__init__(self) .
Saints smokes, B knows nothing about C , and yet super(B,self) knows to call C __init__ ? The reason is that self.__class__.mro() contains C In other words, self (or higher, foo ) knows about C
Therefore, be careful - they are not interchangeable. They can give completely different results.
Using super has pitfalls. It requires a significant level of coordination between all classes of the inheritance diagram. (They should, for example, have the same call signature for __init__ , since any particular __init__ did not know which other __init__ super could call the next, or else use **kwargs .) In addition, you must be compatible using super everywhere. Skip it once (as in the example above) and you will defeat the goal of the super target. See Link for other pitfalls.
If you have full control over the class hierarchy or you avoid diamonds of inheritance, then there is no need for super .