super and __init__

Discussion in 'Python' started by Noah, Sep 8, 2006.

  1. Noah

    Noah Guest

    Am I the only one that finds the super function to be confusing?

    I have a base class that inherits from object.
    In other words new style class:

    class foo (object):
    def __init__ (self, arg_A, arg_B):
    self.a = arg_A
    self.b = arg_B
    # Do I need to call __init__ on "object" base class?

    class bar (foo):
    def __init__ (self, arg_Z):
    self.z = "Z" + arg_Z
    foo.__init__(self, 'A', arg_Z) # this is the old-style
    class way
    def __str__ (self):
    return self.a + self.b + self.z

    I don't know how people will use the "bar" class
    in terms of inheritance. I don't want to lock anyone
    out of multiple inheritance, but I'd like to have to
    worry about it as little as possible. From what I've
    read using the old style of calling the
    base class __init__ can cause conflicts
    if the class is later part of a diamond relationship.

    I just want "bar" to initialize the properties that it add
    to the base class and to have it tell the base class to
    initialize the inherited properties. The old way seemed
    clear enough; although, a bit ugly. The super function
    seems like it would make this more clear, but
    it doesn't (to me).

    Is there a "just do this" answer for 90% of the use cases?

    Yours,
    Noah
     
    Noah, Sep 8, 2006
    #1
    1. Advertising

  2. Noah

    Jason Guest

    Noah wrote:
    > Am I the only one that finds the super function to be confusing?
    >
    > I have a base class that inherits from object.
    > In other words new style class:
    >
    > class foo (object):
    > def __init__ (self, arg_A, arg_B):
    > self.a = arg_A
    > self.b = arg_B
    > # Do I need to call __init__ on "object" base class?
    >
    > class bar (foo):
    > def __init__ (self, arg_Z):
    > self.z = "Z" + arg_Z
    > foo.__init__(self, 'A', arg_Z) # this is the old-style
    > class way
    > def __str__ (self):
    > return self.a + self.b + self.z
    >
    > I don't know how people will use the "bar" class
    > in terms of inheritance. I don't want to lock anyone
    > out of multiple inheritance, but I'd like to have to
    > worry about it as little as possible. From what I've
    > read using the old style of calling the
    > base class __init__ can cause conflicts
    > if the class is later part of a diamond relationship.
    >
    > I just want "bar" to initialize the properties that it add
    > to the base class and to have it tell the base class to
    > initialize the inherited properties. The old way seemed
    > clear enough; although, a bit ugly. The super function
    > seems like it would make this more clear, but
    > it doesn't (to me).
    >
    > Is there a "just do this" answer for 90% of the use cases?
    >
    > Yours,
    > Noah


    As far as I can tell, the best way to use super() with an __init__
    function is to stick to a rigid function signiture. This means, all
    __init__'s must either have the same functions, accept parameters in
    the same order (and handle excess parameters through the *args
    mechanism), or use keyword arguments (using the **keyargs mechanism).

    So, use one of the following for all your classes in the hierarchy:
    def __init__(self, arg1, arg2): # No subclass can add or remove
    arguments
    pass

    def __init__(self, arg1, arg2, *args):
    # Subclasses can add arguments, but cannot remove or have a
    different
    # argument order. The instances must be created with all possible
    parameters.
    pass

    def __init__(self, arg1, arg2, **keyargs):
    # Subclasses can add or remove arguments, and order doesn't matter.
    # The instances must be created with all possible keyword
    parameters.
    pass

    Unfortunately, I don't see a way of avoiding this problem with super().
    Any such super command resolves in the mro order. Since the mro order
    invoked at a certain class can change depending on its subclasses,
    there's no way for the class to predict at design time what super() is
    going to return. You can predict what will be returned with your class
    hierarchy, but another programmer can create a multiple-inheritence
    class that will change the result.

    Explicitly calling the base class is much easier, but a given class
    method can be called multiple times in that case.

    I do wish there was a way to kinda combine the two methods: Explicitly
    call the super-classes, but do so that each super-method can get called
    one or no times. Unfortunately, I haven't (yet) found a way to do so
    that can resolve things right.

    That's not to say that there isn't a better way. I'm sure that the
    Python developers had a devil of a time working on this thing.

    --Jason
     
    Jason, Sep 8, 2006
    #2
    1. Advertising

  3. Noah

    Noah Guest

    Jason wrote:
    > Noah wrote:
    > > Am I the only one that finds the super function to be confusing?

    >
    > Unfortunately, I don't see a way of avoiding this problem with super().
    > Any such super command resolves in the mro order. Since the mro order
    > invoked at a certain class can change depending on its subclasses,
    > there's no way for the class to predict at design time what super() is
    > going to return. You can predict what will be returned with your class
    > hierarchy, but another programmer can create a multiple-inheritence
    > class that will change the result.
    >
    > Explicitly calling the base class is much easier, but a given class
    > method can be called multiple times in that case.


    If I know that multiple calls to my base class __init__ is harmless
    and multiple calls to my derrived class __init__ is harmless then
    is it best to just go ahead and use the old style of explicitly calling
    the __init__? I'm just worried about using the old style base __init__
    call
    with new style objects.

    Since inheritance is so fundemental to an object oriented language
    it's bad that Python makes it so easy to get the constructor wrong.

    Yours,
    Noah
     
    Noah, Sep 8, 2006
    #3
  4. Noah

    Duncan Booth Guest

    "Jason" <> wrote:

    > As far as I can tell, the best way to use super() with an __init__
    > function is to stick to a rigid function signiture.

    ....
    > Unfortunately, I don't see a way of avoiding this problem with super().


    An easy way to avoid changing the method signature is to use a multi-stage
    construction. So if your class hierarchy uses:

    def __init__(self, foo, bar):
    super(ThisClass, self).__init__(foo, bar)
    ... whatever ...

    and you are adding another class to the hierarchy, but that needs a 'baz'
    as well, don't change the signature for __init__, add another method:

    def set_baz(self, baz): ...

    Then at the point you construct the objects you can call:

    x = DerivedClass(foo, bar)
    x.set_baz(baz)

    If set_baz isn't called then you either use a default value or throw an
    error when something depends on it having been set.
     
    Duncan Booth, Sep 9, 2006
    #4
  5. Noah wrote:
    > Am I the only one that finds the super function to be confusing?


    No, see for instance http://fuhm.net/super-harmful/

    Michele Simionato
     
    Michele Simionato, Sep 11, 2006
    #5
    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,789
    Darryl Pierce
    Feb 24, 2005
  2. Steven Bethard
    Replies:
    2
    Views:
    458
    Steven Bethard
    Feb 16, 2005
  3. Kent Johnson
    Replies:
    7
    Views:
    915
    Jan Niklas Fingerle
    Feb 12, 2006
  4. Hugh Sasse Staff Elec Eng

    Inheriting variables, super, and "not super"?

    Hugh Sasse Staff Elec Eng, Dec 9, 2003, in forum: Ruby
    Replies:
    7
    Views:
    125
    Hugh Sasse Staff Elec Eng
    Dec 11, 2003
  5. Ramchandra Apte
    Replies:
    17
    Views:
    342
    Manuel Pégourié-Gonnard
    Sep 30, 2012
Loading...

Share This Page