I see everywhere examples that super-class methods should be called by:
super(SuperClass, instance).method(args)
Is there any disadvantage to doing:
SuperClass.method(instance, args)
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__')
# super(B,self).__init__()
A.__init__(self)
class C(A):
def __init__(self):
print('Running C.__init__')
super(C,self).__init__()
class D(B,C):
def __init__(self):
print('Running D.__init__')
super(D,self).__init__()
foo=D()
So the classes form a so-called inheritance diamond:
A
/ \
B C
\ /
D
Running the code yields
Running D.__init__
Running B.__init__
Running A.__init__
That's bad because C
's __init__
is skipped. The reason for that is because B
's __init__
calls A
's __init__
directly.
The purpose of super
is to resolve inheritance diamonds. If you un-comment
# super(B,self).__init__()
and comment-out
A.__init__(self)
the code yields the more desireable result:
Running D.__init__
Running B.__init__
Running C.__init__
Running A.__init__
Now all the __init__
methods get called. Notice that at the time you define B.__init__
you might think that super(B,self).__init__()
is the same as calling A.__init__(self)
, but you'd be wrong. In the above situation, super(B,self).__init__()
actually calls C.__init__(self)
.
Holy smokes, B
knows nothing about C
, and yet super(B,self)
knows to call C
's __init__
? The reason is because self.__class__.mro()
contains C
. In other words, self
(or in the above, foo
) knows about C
.
So be careful -- the two are not fungible. They can yield vastly different results.
Using super
has pitfalls. It takes a considerable level of coordination between all the classes in the inheritance diagram. (They must, for example, either have the same call signature for __init__
, since any particular __init__
would not know which other __init__
super
might call next, or
else use **kwargs
.) Furthermore, you must be consistent about using super
everywhere. Skip it once (as in the above example) and you defeat the entire purpose of super
.
See the link for more pitfalls.
If you have full control over your class hierarchy, or you avoid inheritance diamonds, then there is no need for super
.