Seb
Seb

Reputation: 105

Python Inheritance and super()

Why does calling Parent classes with super() does not work while using 'direct' call works fine?

class A(object):
    def __init__(self, x):
        self.x = x
        print("Inside A __init__. x = %s" % self.x)
class B(object):
    def __init__(self, y):
        self.y = y
        print("Inside B __init__. y = %s" % self.y)
class C(A,B):
    def __init__(self, z):
        super(C, self).__init__(6)
        super(C, self).__init__(5)
        #1.    A.__init__(self,6)
        #2.    B.__init__(self,5)
        self.z = z
        print("Inside C __init__. z = %s" % self.z)
if __name__ == "__main__":
    log = C(2)

With uncommented 'super' the result I am getting is:

Inside A __init__. x = 6
Inside A __init__. x = 5
Inside C __init__. z = 2

so the code for 'B' class init is never called. But after using the commented lines '#1', and '#2' the code works as it should:

Inside A __init__. x = 6
Inside B __init__. y = 5
Inside C __init__. z = 2

Questions:

  1. What is the cause of this strange 'super()' behaviour.
  2. Can super() call the init in 'B'?
  3. Is there any other way of calling all 'init's from Parent classes?

Upvotes: 2

Views: 172

Answers (1)

chepner
chepner

Reputation: 530920

An answer, which should rather be considered an example of how super works rather than how to actually write code:

class A(object):
    def __init__(self, x):
        self.x = x
        print("Inside A __init__. x = %s" % self.x)
class B(object):
    def __init__(self, y):
        self.y = y
        print("Inside B __init__. y = %s" % self.y)
class C(A,B):
    def __init__(self, z):
        super(C, self).__init__(6)
        super(A, self).__init__(5)
        self.z = z
        print("Inside C __init__. z = %s" % self.z)
if __name__ == "__main__":
    log = C(2)

Each class has a method resolution order (MRO), which is used when looking up inherited functions. For C, that order is

>>> C.__mro__
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)

super(foo, bar) provides a reference to (really, a proxy for) the next class after foo in the MRO of type(bar). super(C, self) provides a reference (really, a proxy) to A, so that A.__init__ is the resulting call. super(A, self), however, provides a proxy to B, resulting in a call to B.__init__.

The general rule, though, is that you really don't know what method will be called next, since you don't necessarily know the type of self (it could be a instance of a descendent class with a different MRO than an instance of C). To use super properly, you need to ensure that all potential classes are using it, so that methods will always be dispatched properly.

Upvotes: 3

Related Questions