2

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?
3
  • it's classic: "Raymond Hettinger - Super considered super! ", youtube.com/watch?v=EiOglTERPEo Commented Nov 10, 2015 at 20:26
  • TL;DR: super is not a drop-in replacement for accessing a specific parent class. Its use must be coordinated among all the classes involved. Commented Nov 10, 2015 at 20:32
  • For those who don't like video, here's the original source material: rhettinger.wordpress.com/2011/05/26/super-considered-super Commented Nov 10, 2015 at 20:55

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

you can add mro() for each example, i guess it may be helpful.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.