First thing that comes to mind : why do I need to name the superclass
explicitly, instead of passing in
self.__class__ (or better still,
class Base(object): def method(self): print 'original' class Derived(Base): def method(self): print 'derived' super(type(self), self).method() class Subclass(Derived): def method(self): print 'subclass of derived' super(Subclass, self).method()
>>> Subclass().method() subclass of derived derived derived derived <...> File "<stdin>", line 4, in method File "<stdin>", line 4, in method File "<stdin>", line 4, in method RuntimeError: maximum recursion depth exceeded while calling a Python object
And this pretty much explains the second question I had. In Python’s Super is nifty, but you can’t use it (Previously: Python’s Super Considered Harmful) we read:
People omit calls to
super(...).__init__if the only superclass is ‘object’, as, after all,
object.__init__doesn’t do anything! However, this is very incorrect. Doing so will cause other classes'
__init__methods to not be called.
But it does not say why (btw not all of the examples compile - see this link also for a nice hack when you need to have arguments passed in the init method, and can’t pop them one by one).
The why is multiple inheritance.
super(...).__init__ in a class whose only superclass is ‘object’ is
useless. But when we have a MI hierarchy, and our “penultimate” base class
(that is the one that inherits directly from object)
is used as a superclass in an unrelated MI class the call
will not delegate to object init but in the next class in the MRO.
class Service(object): def __init__(self, host, binary, topic, manager, report_interval=None, periodic_interval=None, *args, **kwargs): print 'Initializing Service' super(Service, self).__init__(*args, **kwargs) class Color(object): def __init__(self, color='red', **kwargs): print 'Initializing Color' self.color = color super(Color, self).__init__(**kwargs) class ColoredService(Service, Color): def __init__(self, *args, **kwds): print 'Initializing Colored Service' super(ColoredService, self).__init__(*args, **kwds) c = ColoredService('host', 'bin', 'top', 'mgr', 'ivl', color='blue')
Initializing Colored Service Initializing Service Initializing Color
Why ? The call
super(Service, self).__init__(*args, **kwargs) calls the next method in self’s MRO - self being an instance of ColoredService. So the MRO is derived from the instance passed into super’s second argument (you may also pass a type, haven’t gone into this) while the starting point in the MRO is derived from super’s first argument.
And that explains why one must always call super in a method meant to be overridden in a MI setting but when we need also the super class implementation.
Btw for Java people - there is no automatic constructor call in Python.
You must call
super.__init__ manually and that’s where this post comes from.