Python extending with - using super() Python 3 vs Python 2 Python extending with - using super() Python 3 vs Python 2 python python

Python extending with - using super() Python 3 vs Python 2


  • super() (without arguments) was introduced in Python 3 (along with __class__):

    super() -> same as super(__class__, self)

    so that would be the Python 2 equivalent for new-style classes:

    super(CurrentClass, self)
  • for old-style classes you can always use:

     class Classname(OldStyleParent):    def __init__(self, *args, **kwargs):        OldStyleParent.__init__(self, *args, **kwargs)


In a single inheritance case (when you subclass one class only), your new class inherits methods of the base class. This includes __init__. So if you don't define it in your class, you will get the one from the base.

Things start being complicated if you introduce multiple inheritance (subclassing more than one class at a time). This is because if more than one base class has __init__, your class will inherit the first one only.

In such cases, you should really use super if you can, I'll explain why. But not always you can. The problem is that all your base classes must also use it (and their base classes as well -- the whole tree).

If that is the case, then this will also work correctly (in Python 3 but you could rework it into Python 2 -- it also has super):

class A:    def __init__(self):        print('A')        super().__init__()class B:    def __init__(self):        print('B')        super().__init__()class C(A, B):    passC()#prints:#A#B

Notice how both base classes use super even though they don't have their own base classes.

What super does is: it calls the method from the next class in MRO (method resolution order). The MRO for C is: (C, A, B, object). You can print C.__mro__ to see it.

So, C inherits __init__ from A and super in A.__init__ calls B.__init__ (B follows A in MRO).

So by doing nothing in C, you end up calling both, which is what you want.

Now if you were not using super, you would end up inheriting A.__init__ (as before) but this time there's nothing that would call B.__init__ for you.

class A:    def __init__(self):        print('A')class B:    def __init__(self):        print('B')class C(A, B):    passC()#prints:#A

To fix that you have to define C.__init__:

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

The problem with that is that in more complicated MI trees, __init__ methods of some classes may end up being called more than once whereas super/MRO guarantee that they're called just once.


In short, they are equivalent. Let's have a history view:

(1) at first, the function looks like this.

    class MySubClass(MySuperClass):        def __init__(self):            MySuperClass.__init__(self)

(2) to make code more abstract (and more portable). A common method to get Super-Class is invented like:

    super(<class>, <instance>)

And init function can be:

    class MySubClassBetter(MySuperClass):        def __init__(self):            super(MySubClassBetter, self).__init__()

However requiring an explicit passing of both the class and instance break the DRY (Don't Repeat Yourself) rule a bit.

(3) in V3. It is more smart,

    super()

is enough in most case. You can refer to http://www.python.org/dev/peps/pep-3135/