Should one always add super().__init__() to the __init__?

Discussion in 'Python' started by Ramchandra Apte, Sep 29, 2012.

  1. Should one always add super().__init__() to the __init__? The reason for this is the possibility of changing base classes (and forgetting to update the __init__).
    Ramchandra Apte, Sep 29, 2012
    #1
    1. Advertising

  2. On Saturday, 29 September 2012 18:57:48 UTC+5:30, Ramchandra Apte wrote:
    > Should one always add super().__init__() to the __init__? The reason for this is the possibility of changing base classes (and forgetting to update the __init__).


    This is my first post so I may be breaching nettique.
    Ramchandra Apte, Sep 29, 2012
    #2
    1. Advertising

  3. Ramchandra Apte

    Ian Kelly Guest

    On Sat, Sep 29, 2012 at 7:27 AM, Ramchandra Apte <> wrote:
    > Should one always add super().__init__() to the __init__? The reason for this is the possibility of changing base classes (and forgetting to update the __init__).


    As long as the class and its subclasses only use single inheritance,
    it makes little difference, so if you think it will reduce the
    maintenance burden, I would say go for it.
    Ian Kelly, Sep 29, 2012
    #3
  4. On Sat, 29 Sep 2012 06:27:47 -0700, Ramchandra Apte wrote:

    > Should one always add super().__init__() to the __init__? The reason for
    > this is the possibility of changing base classes (and forgetting to
    > update the __init__).


    No. Only add code that works and that you need. Arbitrarily adding calls
    to the superclasses "just in case" may not work:



    py> class Spam(object):
    .... def __init__(self, x):
    .... self.x = x
    .... super(Spam, self).__init__(x)
    ....
    py> x = Spam(1)
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 4, in __init__
    TypeError: object.__init__() takes no parameters



    --
    Steven
    Steven D'Aprano, Sep 29, 2012
    #4
  5. On Sat, Sep 29, 2012 at 1:17 PM, Steven D'Aprano
    <> wrote:
    > No. Only add code that works and that you need. Arbitrarily adding calls
    > to the superclasses "just in case" may not work:
    >
    >
    >
    > py> class Spam(object):
    > ... def __init__(self, x):
    > ... self.x = x
    > ... super(Spam, self).__init__(x)
    > ...
    > py> x = Spam(1)
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in <module>
    > File "<stdin>", line 4, in __init__
    > TypeError: object.__init__() takes no parameters


    That's a good thing. We've gone from code that doesn't call the
    initializer and leaves the object in a potentially invalid state
    (silently!), to code that calls the initializer and then fails
    (loudly).

    -- Devin
    Devin Jeanpierre, Sep 29, 2012
    #5
  6. On Sun, Sep 30, 2012 at 3:17 AM, Steven D'Aprano
    <> wrote:
    > No. Only add code that works and that you need. Arbitrarily adding calls
    > to the superclasses "just in case" may not work:
    >
    > py> class Spam(object):
    > ... def __init__(self, x):
    > ... self.x = x
    > ... super(Spam, self).__init__(x)
    > ...
    > py> x = Spam(1)
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in <module>
    > File "<stdin>", line 4, in __init__
    > TypeError: object.__init__() takes no parameters


    That's because you're subclassing something that doesn't take
    parameters and giving it parameters. Of course that won't work. The
    normal and logical thing to do is to pass on only the parameters that
    you know the parent class expects... but that implies knowing the
    parent, so it's kinda moot.

    ChrisA
    Chris Angelico, Sep 29, 2012
    #6
  7. Chris Angelico <> writes:

    > On Sun, Sep 30, 2012 at 3:17 AM, Steven D'Aprano
    > <> wrote:
    >> No. Only add code that works and that you need. Arbitrarily adding calls
    >> to the superclasses "just in case" may not work:
    >>
    >> py> class Spam(object):
    >> ... def __init__(self, x):
    >> ... self.x = x
    >> ... super(Spam, self).__init__(x)
    >> ...
    >> py> x = Spam(1)
    >> Traceback (most recent call last):
    >> File "<stdin>", line 1, in <module>
    >> File "<stdin>", line 4, in __init__
    >> TypeError: object.__init__() takes no parameters

    >
    > That's because you're subclassing something that doesn't take
    > parameters and giving it parameters. Of course that won't work. The
    > normal and logical thing to do is to pass on only the parameters that
    > you know the parent class expects... but that implies knowing the
    > parent, so it's kinda moot.


    It is not necesarily calling the parent class. It calls the initializer
    of the next class in the MRO order and what class that is depends on the
    actual multiple inheritance structure it is used in, which can depend
    on subclasses that you don't know yet. This makes it even worse.
    --
    Piet van Oostrum <>
    WWW: http://pietvanoostrum.com/
    PGP key: [8DAE142BE17999C4]
    Piet van Oostrum, Sep 29, 2012
    #7
  8. On Saturday, 29 September 2012 22:47:20 UTC+5:30, Steven D'Aprano wrote:
    > On Sat, 29 Sep 2012 06:27:47 -0700, Ramchandra Apte wrote:
    >
    >
    >
    > > Should one always add super().__init__() to the __init__? The reason for

    >
    > > this is the possibility of changing base classes (and forgetting to

    >
    > > update the __init__).

    >
    >
    >
    > No. Only add code that works and that you need. Arbitrarily adding calls
    >
    > to the superclasses "just in case" may not work:
    >
    >
    >
    >
    >
    >
    >
    > py> class Spam(object):
    >
    > ... def __init__(self, x):
    >
    > ... self.x = x
    >
    > ... super(Spam, self).__init__(x)
    >
    > ...
    >
    > py> x = Spam(1)
    >
    > Traceback (most recent call last):
    >
    > File "<stdin>", line 1, in <module>
    >
    > File "<stdin>", line 4, in __init__
    >
    > TypeError: object.__init__() takes no parameters
    >
    >
    >
    >
    >
    >
    >
    > --
    >
    > Steven


    I forgot something:
    I meant super().__init__() or similar
    Ramchandra Apte, Sep 30, 2012
    #8
  9. On Sat, 29 Sep 2012 20:14:10 -0700, Ramchandra Apte wrote:

    > I forgot something:
    > I meant super().__init__() or similar


    What about it? Please try to remember that we can't read your mind and
    don't know what you are thinking, we can only work from what you put in
    writing.

    There is no difference between super(Class, self).__init__ and
    super().__init__ except that the second version only works in Python 3.



    --
    Steven
    Steven D'Aprano, Sep 30, 2012
    #9
  10. On Sun, 30 Sep 2012 04:31:48 +1000, Chris Angelico wrote:

    > On Sun, Sep 30, 2012 at 3:17 AM, Steven D'Aprano
    > <> wrote:
    >> No. Only add code that works and that you need. Arbitrarily adding
    >> calls to the superclasses "just in case" may not work:
    >>
    >> py> class Spam(object):
    >> ... def __init__(self, x):
    >> ... self.x = x
    >> ... super(Spam, self).__init__(x) ...
    >> py> x = Spam(1)
    >> Traceback (most recent call last):
    >> File "<stdin>", line 1, in <module>
    >> File "<stdin>", line 4, in __init__
    >> TypeError: object.__init__() takes no parameters

    >
    > That's because you're subclassing something that doesn't take parameters
    > and giving it parameters. Of course that won't work. The normal and
    > logical thing to do is to pass on only the parameters that you know the
    > parent class expects... but that implies knowing the parent, so it's
    > kinda moot.


    Which is exactly my point -- you can't call the superclass "just in case"
    it changes, because you don't know what arguments the new superclass or
    classes expect. You have to tailor the arguments to what the parent
    expects, and even whether or not you have to call super at all.[1]

    super() is not some magic command "don't bother me with the details, just
    make method overriding work". You have to actually think about what you
    are overriding. You can't expect to take a class that inherits from dict
    and change it to inherit from collections.defaultdict and have super
    magically sort out the differences in __init__.

    The usual advise given for using super is:

    * the method being called by super() needs to exist
    * the caller and callee need to have a matching[2] argument signature
    * and every occurrence of the method needs to use super()

    If all three conditions apply, then yes, you should use super. Otherwise,
    perhaps not.

    For further discussion and practical examples, see:

    http://rhettinger.wordpress.com/2011/05/26/super-considered-super/


    For a contrary argument, or at least a look at how NOT to use super, see:

    https://fuhm.net/super-harmful/

    which makes the mistake of blaming super() for mistakes made by people
    who don't use it correctly. Note that the author has back-peddled from
    his original argument that super was actively harmful to a less
    provocative argument that "you can't use super" (except you actually can:
    if you read past the first paragraph, the author tells you exactly what
    you need to do to use super correctly).




    [1] You *should* call super, unless you have an excellent reason not to,
    so that your class doesn't break multiple-inheritance. But you need to do
    so with care making sure that the argument signatures are designed for
    cooperative use of super.

    [2] Matching in this case does not necessarily mean identical.

    --
    Steven
    Steven D'Aprano, Sep 30, 2012
    #10
  11. On Sat, 29 Sep 2012 17:51:29 -0400, Piet van Oostrum wrote:

    > It is not necesarily calling the parent class. It calls the initializer
    > of the next class in the MRO order and what class that is depends on the
    > actual multiple inheritance structure it is used in, which can depend on
    > subclasses that you don't know yet. This makes it even worse.


    I don't quite follow you here. It sounds like you are saying that if you
    have these classes:

    # pre-existing classes
    class A(object): pass
    class B(object): pass

    # your class
    class C(A, B): pass

    and somebody subclasses A or B, the MRO of C will change. That is not
    actually the case as far as I can see.



    --
    Steven
    Steven D'Aprano, Sep 30, 2012
    #11
  12. On Sun, Sep 30, 2012 at 2:37 PM, Steven D'Aprano
    <> wrote:
    > Which is exactly my point -- you can't call the superclass "just in case"
    > it changes, because you don't know what arguments the new superclass or
    > classes expect. You have to tailor the arguments to what the parent
    > expects, and even whether or not you have to call super at all.[1]
    >
    > super() is not some magic command "don't bother me with the details, just
    > make method overriding work". You have to actually think about what you
    > are overriding.


    Yeah. Far as I'm concerned, subclassing should *always* involve
    knowing the parent class. You needn't concern yourself with its
    implementation (I can subclass dict without caring about the details
    of hash randomization), but you have to be aware of its interface. And
    if you change the base class without changing your method chaining,
    you'd better be changing to a new base class that's equivalent to the
    old one.

    The advantage of super() is that you can substitute a subclass of X as
    a new base class without changing anything. But you need to be sure
    that the replacement base class obeys the Liskov Substitution
    Principle.

    ChrisA
    Chris Angelico, Sep 30, 2012
    #12
  13. On Sunday, 30 September 2012 09:53:45 UTC+5:30, Steven D'Aprano wrote:
    > On Sat, 29 Sep 2012 20:14:10 -0700, Ramchandra Apte wrote:
    >
    >
    >
    > > I forgot something:

    >
    > > I meant super().__init__() or similar

    >
    >
    >
    > What about it? Please try to remember that we can't read your mind and
    >
    > don't know what you are thinking, we can only work from what you put in
    >
    > writing.
    >
    >
    >
    > There is no difference between super(Class, self).__init__ and
    >
    > super().__init__ except that the second version only works in Python 3.
    >
    >
    >
    >
    >
    >
    >
    > --
    >
    > Steven


    When I said "super().__init__()" it could have been "super().__init__(size+67)" or whatever arguments are needed for __init__
    Ramchandra Apte, Sep 30, 2012
    #13
  14. Ramchandra Apte

    Ian Kelly Guest

    On Sat, Sep 29, 2012 at 10:40 PM, Steven D'Aprano
    <> wrote:
    > On Sat, 29 Sep 2012 17:51:29 -0400, Piet van Oostrum wrote:
    >
    >> It is not necesarily calling the parent class. It calls the initializer
    >> of the next class in the MRO order and what class that is depends on the
    >> actual multiple inheritance structure it is used in, which can depend on
    >> subclasses that you don't know yet. This makes it even worse.

    >
    > I don't quite follow you here. It sounds like you are saying that if you
    > have these classes:
    >
    > # pre-existing classes
    > class A(object): pass
    > class B(object): pass
    >
    > # your class
    > class C(A, B): pass
    >
    > and somebody subclasses A or B, the MRO of C will change. That is not
    > actually the case as far as I can see.


    The MRO of C will not change, but the class that follows C may be
    different in the MRO of a subclass.
    Ian Kelly, Sep 30, 2012
    #14
  15. Ramchandra Apte

    Ian Kelly Guest

    On Sat, Sep 29, 2012 at 10:55 PM, Ramchandra Apte
    <> wrote:
    > When I said "super().__init__()" it could have been "super().__init__(size+67)" or whatever arguments are needed for __init__


    But if you change the base class, couldn't those arguments change?
    Then you would have to change the call whether super is used or not.
    I believe this is what Steven is getting at.
    Ian Kelly, Sep 30, 2012
    #15
  16. Ramchandra Apte

    Ian Kelly Guest

    On Sat, Sep 29, 2012 at 10:37 PM, Steven D'Aprano
    <> wrote:
    > [1] You *should* call super, unless you have an excellent reason not to,
    > so that your class doesn't break multiple-inheritance. But you need to do
    > so with care making sure that the argument signatures are designed for
    > cooperative use of super.


    I disagree. Most classes will not ever be used for multiple
    inheritance, and the changes involved in "making sure that the
    argument signatures are designed for cooperative use of super" are not
    trivial. For one, it means not being able to use positional arguments
    in __init__ methods. For two, the
    receive-and-strip-off-keyword-arguments approach falls apart if you
    have unrelated classes that take the same arguments. For
    illustration, suppose you have the following two classes, both of
    which use a required Frobnik object to perform their functions.


    class A:
    def __init__(self, frobnik, **kwargs):
    super().__init__(**kwargs)
    self._frobnik = frobnik
    ...

    class B:
    def __init__(self, frobnik, **kwargs):
    super().__init__(**kwargs)
    self._frobnik = frobnik
    ...

    Even though these classes have been designed to be cooperative, they
    cannot be inherited together. Whichever class is first in the MRO
    will receive the frobnik argument and strip it off, and then the other
    class's __init__ method will complain of a missing required argument.

    There are solutions to this. For instance, you could make frobnik
    optional in each class, each one relying on the other to receive the
    frobnik argument if it is missing, but this complicates the
    implementations and makes it difficult to detect in a timely manner if
    the frobnik argument has actually not been supplied. Or you could
    change the name of the argument in one of the classes, but then your
    library users will complain of inconsistent naming.

    What it boils down to is that classes that are expected to be used for
    multiple inheritance should be designed to use super cooperatively,
    but the majority of classes that you write should not have to deal
    with these sorts of restrictions. Classes that will only ever be
    singly inherited should be written normally and using whatever
    superclass call style feels most appropriate.
    Ian Kelly, Sep 30, 2012
    #16
  17. On Sun, 30 Sep 2012 00:08:03 -0600, Ian Kelly wrote:

    > On Sat, Sep 29, 2012 at 10:40 PM, Steven D'Aprano
    > <> wrote:
    >> On Sat, 29 Sep 2012 17:51:29 -0400, Piet van Oostrum wrote:
    >>
    >>> It is not necesarily calling the parent class. It calls the
    >>> initializer of the next class in the MRO order and what class that is
    >>> depends on the actual multiple inheritance structure it is used in,
    >>> which can depend on subclasses that you don't know yet. This makes it
    >>> even worse.

    >>
    >> I don't quite follow you here. It sounds like you are saying that if
    >> you have these classes:
    >>
    >> # pre-existing classes
    >> class A(object): pass
    >> class B(object): pass
    >>
    >> # your class
    >> class C(A, B): pass
    >>
    >> and somebody subclasses A or B, the MRO of C will change. That is not
    >> actually the case as far as I can see.

    >
    > The MRO of C will not change, but the class that follows C may be
    > different in the MRO of a subclass.


    To quote a famous line from the movie Cool Hand Luke, "what we have here,
    is a failure to communicate."

    What do you mean by one class following another? Which class is it that
    follows C? What subclass are you talking about, and what is it
    subclassing?

    I have absolutely no idea what you are trying to get across here, why you
    think it is important, or whether it matches what Piet is trying to say.



    --
    Steven
    Steven D'Aprano, Sep 30, 2012
    #17
  18. Steven D'Aprano scripsit :

    > On Sun, 30 Sep 2012 00:08:03 -0600, Ian Kelly wrote:
    >
    >> On Sat, Sep 29, 2012 at 10:40 PM, Steven D'Aprano
    >> <> wrote:
    >>> On Sat, 29 Sep 2012 17:51:29 -0400, Piet van Oostrum wrote:
    >>>
    >>>> It is not necesarily calling the parent class. It calls the
    >>>> initializer of the next class in the MRO order and what class that is
    >>>> depends on the actual multiple inheritance structure it is used in,
    >>>> which can depend on subclasses that you don't know yet. This makes it
    >>>> even worse.
    >>>
    >>> I don't quite follow you here. It sounds like you are saying that if
    >>> you have these classes:
    >>>
    >>> # pre-existing classes
    >>> class A(object): pass
    >>> class B(object): pass
    >>>
    >>> # your class
    >>> class C(A, B): pass
    >>>
    >>> and somebody subclasses A or B, the MRO of C will change. That is not
    >>> actually the case as far as I can see.

    >>
    >> The MRO of C will not change, but the class that follows C may be
    >> different in the MRO of a subclass.

    >
    > To quote a famous line from the movie Cool Hand Luke, "what we have here,
    > is a failure to communicate."
    >
    > What do you mean by one class following another? Which class is it
    > that follows C? What subclass are you talking about, and what is it
    > subclassing?
    >

    I think Piet's (and Ian's) point is, you can't assume that
    super().__init__, written in a method of C, is always going to refer to
    __init__ of the parent class of C, when a subclass of C is instanciated.

    For example:

    class C:
    def __init__(self):
    print("C init, calling C's parent init?")
    super().__init__() # sic

    class NotParentOfC:
    def __init__(self):
    print("NotParentOfC init")

    class Sub(C, NotParentOfC):
    pass

    spam = Sub()

    When Sub is instantiated, the line marked "sic" calls
    NotParentOfC.__init, not object.__init__ (as if would if C was
    instantiated).

    --
    Manuel Pégourié-Gonnard - http://people.math.jussieu.fr/~mpg/
    Manuel Pégourié-Gonnard, Sep 30, 2012
    #18
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Guest

    super.super.super how?

    Guest, Feb 19, 2005, in forum: Java
    Replies:
    24
    Views:
    10,761
    Darryl Pierce
    Feb 24, 2005
  2. Fernando Rodriguez

    Getting the super class via the super() function

    Fernando Rodriguez, Nov 21, 2003, in forum: Python
    Replies:
    2
    Views:
    720
    Bob Willan
    Nov 22, 2003
  3. Kerim Borchaev

    super. could there be a simpler super?

    Kerim Borchaev, Jan 15, 2004, in forum: Python
    Replies:
    4
    Views:
    476
    Michele Simionato
    Jan 15, 2004
  4. Kent Johnson
    Replies:
    7
    Views:
    911
    Jan Niklas Fingerle
    Feb 12, 2006
  5. Replies:
    7
    Views:
    450
    Patricia Shanahan
    Apr 6, 2008
Loading...

Share This Page