Search code examples
pythonlanguage-design

Why python super does not accept only instance?


In python 2.x, super accepts the following cases

class super(object)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)
 |  Typical use to call a cooperative superclass method:

as far as I see, super is a class, wrapping the type and (eventually) the instance to resolve the superclass of a class.

I'm rather puzzled by a couple of things:

  • why there is also no super(instance), with typical usage e.g. super(self).__init__(). Technically, you can obtain the type of an object from the object itself, so the current strategy super(ClassType, self).__init__() is kind of redundant. I assume compatibility issues with old-style classes, or multiple inheritance, but I'd like to hear your point.
  • why, on the other hand, python 3 will accept (see Understanding Python super() with __init__() methods) super().__init__() ? I see kind of magic in this, violating the explicit is better than implicit Zen. I would have seen more appropriate self.super().__init__().

Solution

  • super(ClassType, self).__init__() is not redundant in a cooperative multiple inheritance scheme -- ClassType is not necessarily the type of self, but the class from which you want to do the cooperative call to __init__.

    In the class hierarchy C inherits B inherits A, in C.__init__ you want to call superclass' init from C's perspective, and you call B.__init__; then in B.__init__ you must pass the class type B to super -- since you want to resolve calling superclasses of B (or rather, the next in the mro after B of the class C).

    class A (object):
      def __init__(self):
        pass
    
    class B (A):
      def __init__(self):
        super(B, self).__init__()
    
    class C (B):
      def __init__(self):
        super(C, self).__init__()
    

    if you now instantiate c = C(), you see that the class type is not redundant -- super(self).__init__() inside B.__init__ would not really work! What you do is that you manually specify in which class the method calling super is (an this is solved in Python 3's super by a hidden variable pointing to the method's class).

    Two links with examples of super and multiple inheritance: