By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,732 Members | 1,388 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,732 IT Pros & Developers. It's quick & easy.

super and __init__

P: n/a
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

Sep 8 '06 #1
Share this Question
Share on Google+
4 Replies


P: n/a
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

Sep 8 '06 #2

P: n/a

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

Sep 8 '06 #3

P: n/a
"Jason" <te***********@gmail.comwrote:
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.

Sep 9 '06 #4

P: n/a
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

Sep 11 '06 #5

This discussion thread is closed

Replies have been disabled for this discussion.