super and __init__

Jason tenax.raccoon at gmail.com
Fri Sep 8 18:00:11 EDT 2006


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




More information about the Python-list mailing list