297

Consider this - a base class A, class B inheriting from A, class C inheriting from B. What is a generic way to call a parent class initialiser in an initialiser? If this still sounds too vague, here's some code.

class A(object):
    def __init__(self):
        print "Initialiser A was called"

class B(A):
    def __init__(self):
        super(B,self).__init__()
        print "Initialiser B was called"

class C(B):
    def __init__(self):
        super(C,self).__init__()
        print "Initialiser C was called"

c = C()

This is how I do it now. But it still seems a bit too non-generic - you still must pass a correct type by hand.

Now, I've tried using self.__class__ as a first argument to super(), but, obviously it doesn't work - if you put it in the initialiser for C - fair enough, B's initialiser gets called. If you do the same in B, "self" still points to an instance of C so you end up calling B's initialiser again (this ends in an infinite recursion).

There is no need to think about diamond inheritance for now, I am just interested in solving this specific problem.

bignose
  • 30,281
  • 14
  • 77
  • 110
shylent
  • 10,076
  • 6
  • 38
  • 55
  • "But it still seems a bit too non-generic - you still must pass a correct type by hand."?? You're passing the class name to super(). You never need to know the superclass or anything else. How is this non-generic? What problem does it create? Can you give an example where this breaks? – S.Lott May 24 '09 at 17:08
  • 3
    I am not ready to answer this question if full. But anyway, what if the class gets renamed? What if I want to write a decorator function to automate this kind of chaining? Now I see, that this is not possible, but at the time of asking the question I did not know that. – shylent May 24 '09 at 17:27
  • @shylent, if I understand your question, what your describing is possible. You can use super() to make parent references fully generic if you understand the mro. Google "python super is super", watch the video. – Jamie Marshall Sep 04 '18 at 22:59
  • @shylent actually, reading your question again I believe the infinite recursion you're experiencing is not what you think it is. I believe the mro order is making you call a constructor you're not intending to. I just dealt with this same thing myself not long ago. No matter what you pass to the first argument of super, super will call the first constructor in the mro, not the type you passed in. For instance if you call super(self.__class__, self) in the constructor of C, you will still call B's constructor because it is the first parent in the mro. – Jamie Marshall Sep 04 '18 at 23:04

3 Answers3

217

Python 3 includes an improved super() which allows use like this:

super().__init__(args)
ironfroggy
  • 7,991
  • 7
  • 33
  • 44
  • 3
    if I have more than one parent class how will super identify the which parent class to invoke ? – Kracekumar Aug 13 '11 at 20:02
  • 2
    @kracekumar It will be determined by the class' Method Resolution Order (MRO), which you can find out by calling `MyClassName.mro()`. I may be incorrect, but I believe that the first specified parent is the one whose `__init__` will be called. – Cam Jackson Aug 16 '11 at 02:14
  • @ironfroggy, would you mind elaborating on How does this improved super help with the question? I just found this old thread and I am having the same exact questions. Also Have things improved for Python 2.x since this question was first asked? – Amelio Vazquez-Reina Apr 04 '13 at 16:53
  • 1
    @user815423426 Because it makes the up-calls more generic, no longer repeating the class name, which was the subject of the original question. – ironfroggy Sep 15 '13 at 18:17
  • @kracekumar, super(X,obj) actually returns a special "super" object that, when you do an attribute access on it, will return the attribute that would have been returned had class X had no attributes at all. for example, super(X,obj).__init__ will return the __init__ method of your obj as if __init__ in class X not been there. Now, if class X has two parents, and X.__init__ doesnt exist, the default behavior is to call __init__ of only _one_ of the parents, not both. This is effectively what super is doing... giving you one of the parents. – Chris Cogdon Mar 25 '15 at 19:21
170

The way you are doing it is indeed the recommended one (for Python 2.x).

The issue of whether the class is passed explicitly to super is a matter of style rather than functionality. Passing the class to super fits in with Python's philosophy of "explicit is better than implicit".

dF.
  • 74,139
  • 30
  • 130
  • 136
  • 3
    I've had a really hard time deciding which answer to accept, but I will accept this one, simply because it is relevant to the version of python I am using. – shylent May 24 '09 at 19:51
  • 9
    In Python 2.6 I get `TypeError: super() argument 1 must be type, not classobj` using this method. Am I missing something? – Leopd May 26 '10 at 23:30
  • 13
    @Leopd: `super()` only works with new-style classes, i.e. you must inherit from `object`. – dF. May 28 '10 at 20:25
  • How on earth can you possibly say Python's philosophy is "explicit is better than implicit". It's not a strongly typed language. – Philluminati Dec 06 '10 at 12:45
  • 1
    @Philluminati: See http://www.python.org/dev/peps/pep-0020/ – dF. Dec 12 '10 at 21:33
  • 21
    Python IS a strongly typed language, but it is dynamically typed. There is a difference between weak and dynamic typing. – Josh Smeaton Dec 19 '10 at 11:45
  • In Python 2.7 you get: **TypeError: must be type, not classobj** – David Newcomb Feb 21 '11 at 17:14
  • @JoshSmeaton: I would definitely not categorise Python as being strongly typed. The definition varies, I guess, but to me a strongly typed language is one where all variables and parameters must have a type. This is just not the case in Python. I can call methods on a variable without having any idea what object it is or what type it is. As long as that type has that method with the correct input parameters, it is called. I'm not starting a discussion about the definition of strongly typed. I just want an opposing opinion to appear in this list to show that you're not necessarily right. :) – The Science Boy Jul 24 '15 at 09:27
  • 2
    @TheScienceBoy the definitions are clear though. Python is strong-dynamic. Something like Java is strong-static. PHP is weak-dynamic. Static typing guarantees (within some limits at least) that input parameters are the correct type. Strong typing means that the compiler/runtime will not attempt to coerce the *value* of one type to another.. like changing "1" to a 1 so you can do math on it. Please see here: https://wiki.python.org/moin/Why%20is%20Python%20a%20dynamic%20language%20and%20also%20a%20strongly%20typed%20language – Josh Smeaton Jul 26 '15 at 23:23
  • This answer really doesn't make sense for being explicit, and you may find that passing the class to the super(cls, instance) call does not do what you want. It actually implicitly - calls the parent class based on [method resolution order](https://docs.python.org/3/library/stdtypes.html?highlight=mro#class.mro). You can google more about it from here. To explicitly call a class constructor as you suggest you should go with @Jay Parikh 's answer. Using super() is all about implicit reference so as to decouple the class from its parent. – Jamie Marshall Sep 04 '18 at 22:51
29

You can simply write :

class A(object):

    def __init__(self):
        print "Initialiser A was called"

class B(A):

    def __init__(self):
        A.__init__(self)
        # A.__init__(self,<parameters>) if you want to call with parameters
        print "Initialiser B was called"

class C(B):

    def __init__(self):
        # A.__init__(self) # if you want to call most super class...
        B.__init__(self)
        print "Initialiser C was called"
bignose
  • 30,281
  • 14
  • 77
  • 110
Jay Parikh
  • 2,419
  • 17
  • 13