Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - which is the better way of calling superclass' method?

Tags:

python

oop

class

All the while I have been using:

SuperClass.__init__(self, *args, **kwargs)

My reason is that this shows explicitly which superclass is used, especially in the case of multiple inheritance.

However, other codes I came across use

super(MyClass, self).__init__(*args, **kwargs)

instead.

This could become ambigious when it's used in:

class MyClass(SuperClass1, SuperClass2):
    def __init__(self, *args, **kwargs):
        super(MyClass, self).__init__(*args, **kwargs) #which SuperClass is being used?

I would like to know why this form of calling is widely adopted? Any advantage at all?

like image 857
kakarukeys Avatar asked Nov 29 '10 03:11

kakarukeys


People also ask

How do you call a super method in Python?

Using Super(): Python super() function provides us the facility to refer to the parent class explicitly. It is basically useful where we have to call superclass functions. It returns the proxy object that allows us to refer parent class by 'super'.

Which Python function can be used to call a method of a superclass?

An Overview of Python's super() Function super() alone returns a temporary object of the superclass that then allows you to call that superclass's methods.

Is super () necessary Python?

In general it is necessary. And it's often necessary for it to be the first call in your init. It first calls the init function of the parent class ( dict ).

Why do we need super () in an extended class Python?

The super() function in Python makes class inheritance more manageable and extensible. The function returns a temporary object that allows reference to a parent class by the keyword super.


2 Answers

The reason that super is prefereable for modern (new style) classes is that it allows cooperative multiple inheritance. Here's an example.

>>> class Foo(object):
...     def display(self):
...         print "In Foo"
... 
>>> class Foo2(Foo):
...     def display(self):
...         print "In Foo2"
...         super(Foo2, self).display()
...         print "Back in Foo2"
... 
>>> class Bar(Foo):
...     def display(self):
...         print "In Bar"
...         super(Bar, self).display()
...         print "Back in Bar"
... 
>>> class FooBar(Foo2, Bar):
...     pass
... 
>>> FooBar().display()
In Foo2
In Bar
In Foo
Back in Bar
Back in Foo2
>>> class BarFoo(Bar, Foo2):
...     pass
... 
>>> BarFoo().display()
In Bar
In Foo2
In Foo
Back in Foo2
Back in Bar

Note that I didn't do anything to change the display method on the superclasses but I got different display methods on the subclasses by changing the order in which I arranged the superclasses. BarFoo and FooBar have different methods. This is because they have different Method Resolution Orders

>>> BarFoo.__mro__
(<class '__main__.BarFoo'>, <class '__main__.Bar'>, <class '__main__.Foo2'>, <class '__main__.Foo'>, <type 'object'>)
>>> FooBar.__mro__
(<class '__main__.FooBar'>, <class '__main__.Foo2'>, <class '__main__.Bar'>, <class '__main__.Foo'>, <type 'object'>)

This means that super resolves to a different class for each subclass that it's called in. This allows for each overriding method to change a small part of what's going on and still let every other superclass contribute to the method call as long as they're willing to play nicely.

like image 164
aaronasterling Avatar answered Nov 02 '22 20:11

aaronasterling


For new style classes which inherit from object, super is used.

The __mro__ (method resolution order) attribute of the type lists the method resolution search order used by super.

>>> class X(object):
    pass

>>> class Y(object):
    pass

>>> class Z(X, Y):
    pass

>>> Z.__mro__
(<class '__main__.Z'>, <class '__main__.X'>, <class '__main__.Y'>, <type 'object'>)

This specifies the ordering for Z. Since it is Z(X, Y), X is first in the hierarchy. Had it been Z(Y, X), Y would have preceded over X.

For old style classes, SuperClass.__init__(self, *args, **kwargs) is used.

UPDATE:

For your question as to which SuperClass is being used.

>>> class First(object):
    pass

>>> class Second(object):
    def __init__(self, *args, **kwargs):
        print 'Second __init__ called'

>>> class MInherit(First, Second):
    def __init__(self):
        super(MInherit, self).__init__()

>>> i = MInherit()
Second __init__ called

First, First will be checked to see if it has an __init__, since First comes first in the MRO. Since in this case 'First' doesn't have an __init__, so Second is called. Had there been an __init__ in First, only that would have been called.

like image 30
user225312 Avatar answered Nov 02 '22 21:11

user225312