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

Dispatch with multiple inheritance

P: n/a
Consider the following class hierarchy in Python:

class A (object):
def __init__(self):
print "cons A"

class B (object):
def __init__(self):
print "cons B"

class C (A):
def __init__(self):
super(C, self).__init__()
print "cons C"

class D (B):
def __init__(self):
super(D, self).__init__()
print "cons D"

Now, suppose I would like to define a new class as follows:

class E (C, D):
...

In the constructor for E, I would like to invoke the constructors of
both parent classes. The correct way to do this seems to be exemplified
by the following:

class E (C, D):
def __init__(self):
super(E, self).__init__() # calls C constructor
super(A, self).__init__() # calls D constructor (**)
print "cons E"

This works, but I find it somewhat troubling. It seems to me that one
should not have to "know" (i.e., write down the names of) the ancestors
of C in order to dispatch to superclass methods in D, since C and D
share no common ancestors south of object.

Is there a better (i.e., more elegant) way to handle the case marked
(**) above?

Curious,
-M

--
Michael J. Fromberger | Lecturer, Dept. of Computer Science
http://www.dartmouth.edu/~sting/ | Dartmouth College, Hanover, NH, USA
Jul 18 '06 #1
Share this Question
Share on Google+
8 Replies


P: n/a
Michael,
You only need to call the __init__ method of the superclass if you need
to do something special during initialization. In general I just use
the SuperClass.__init__(self,...) way of calling the super class
constructors. This way, I only initialize the immediate parents and
they will in turn call the init method of their parents and so on.
super() is probably the a better way to do things but I find
SuperClass.__init__(self, ...) more clear. For example your code would
be:
-------------------------------
class A (object):
def __init__(self):
print "cons A"

class B (object):
def __init__(self):
print "cons B"

class C (A):
def __init__(self):
A.__init__(self)
print "cons C"

class D (B):
def __init__(self):
B.__init__(self)
print "cons D"

class E(D,C):
def __init__(self):
C.__init__(self)
D.__init__(self)
print "cons E"

e=E()
----------------------------------
Output should be:
cons A
cons C
cons B
cons D
cons E

In general note that __init__ is NOT a constuctor it is an initializer
(therefore the name __init__ as opposed to __constr__ or __new__). The
object is constructed by Python already and is given to init method as
the 'self' argument. The construction can also be customized inside the
__new__ magic method, but normally you don't even need to know about
__new__.

Hope this helps,
Nick V.

Michael J. Fromberger wrote:
Consider the following class hierarchy in Python:

class A (object):
def __init__(self):
print "cons A"

class B (object):
def __init__(self):
print "cons B"

class C (A):
def __init__(self):
super(C, self).__init__()
print "cons C"

class D (B):
def __init__(self):
super(D, self).__init__()
print "cons D"

Now, suppose I would like to define a new class as follows:

class E (C, D):
...

In the constructor for E, I would like to invoke the constructors of
both parent classes. The correct way to do this seems to be exemplified
by the following:

class E (C, D):
def __init__(self):
super(E, self).__init__() # calls C constructor
super(A, self).__init__() # calls D constructor (**)
print "cons E"

This works, but I find it somewhat troubling. It seems to me that one
should not have to "know" (i.e., write down the names of) the ancestors
of C in order to dispatch to superclass methods in D, since C and D
share no common ancestors south of object.

Is there a better (i.e., more elegant) way to handle the case marked
(**) above?

Curious,
-M

--
Michael J. Fromberger | Lecturer, Dept. of Computer Science
http://www.dartmouth.edu/~sting/ | Dartmouth College, Hanover, NH, USA
Jul 18 '06 #2

P: n/a
Michael J. Fromberger ha scritto:
Consider the following class hierarchy in Python:
<snip>
Is there a better (i.e., more elegant) way to handle the case marked
(**) above?

Curious,
-M

--
Michael J. Fromberger | Lecturer, Dept. of Computer Science
http://www.dartmouth.edu/~sting/ | Dartmouth College, Hanover, NH, USA
Look at
http://www.python.org/download/releases/2.3/mro
Michele Simionato

Jul 19 '06 #3

P: n/a
Michael J. Fromberger wrote:
>
Is there a better (i.e., more elegant) way to handle the case marked
(**) above?
You have to call super in each method __init__, if you don't, the call
chain break before the end:

class A (object):
def __init__(self):
super(A, self).__init__()
print "cons A"

class B (object):
def __init__(self):
super(B, self).__init__()
print "cons B"

class C (A):
def __init__(self):
super(C, self).__init__()
print "cons C"

class D (B):
def __init__(self):
super(D, self).__init__()
print "cons D"

class E (C, D):
def __init__(self):
super(E, self).__init__() # calls C constructor
print "cons E"

Jul 19 '06 #4

P: n/a

looping wrote:
Michael J. Fromberger wrote:

Is there a better (i.e., more elegant) way to handle the case marked
(**) above?

You have to call super in each method __init__, if you don't, the call
chain break before the end:

class A (object):
def __init__(self):
super(A, self).__init__()
print "cons A"

class B (object):
def __init__(self):
super(B, self).__init__()
print "cons B"

class C (A):
def __init__(self):
super(C, self).__init__()
print "cons C"

class D (B):
def __init__(self):
super(D, self).__init__()
print "cons D"

class E (C, D):
def __init__(self):
super(E, self).__init__() # calls C constructor
print "cons E"
After a second tought, it's probably better to call __init__ method
explicitly in class E:

class A (object):
def __init__(self):
print "cons A"

class B (object):
def __init__(self):
print "cons B"

class C (A):
def __init__(self):
super(C, self).__init__()
print "cons C"

class D (B):
def __init__(self):
super(D, self).__init__()
print "cons D"

class E (C, D):
def __init__(self):
D.__init__(self)
C.__init__(self)
print "cons E"

this way you have to choose which __init__ from class D or class C is
calling, and which is calling first.
Any Python Guru to give is opinion ?

Jul 19 '06 #5

P: n/a
In article <11*********************@s13g2000cwa.googlegroups. com>,
"Michele Simionato" <mi***************@gmail.comwrote:
Michael J. Fromberger ha scritto:
Consider the following class hierarchy in Python:
<snip>
Is there a better (i.e., more elegant) way to handle the case marked
(**) above?

Curious,
-M

--
Michael J. Fromberger | Lecturer, Dept. of Computer Science
http://www.dartmouth.edu/~sting/ | Dartmouth College, Hanover, NH, USA

Look at
http://www.python.org/download/releases/2.3/mro
Hi, Michele,

I understand what Python's method resolution order is, and how it is
constructed. Is there something else in that article, that you hoped
would address my original concern? In particular, I am not asking WHY
super(A, self).__init()__ yields the next method in order -- that is
quite clear. Rather, I want to know if there is a better way to invoke
the ancestry of class E from D, than to explicitly denote the ancestry
of C in the code. The latter is an ugly violation of abstraction, and
renders the class hierarchy brittle.

Of course, I could just bypass super, and explicitly invoke them as:

C.__init__(self, ...)
D.__init__(self, ...)

.... but that seems to me to defeat the purpose of having super in the
first place.

It seems as if perhaps there is no better solution at present. That is
a pity, albeit a mild one. Thank you for taking the time to respond.

-M

--
Michael J. Fromberger | Lecturer, Dept. of Computer Science
http://www.dartmouth.edu/~sting/ | Dartmouth College, Hanover, NH, USA
Jul 19 '06 #6

P: n/a
In article <11**********************@m73g2000cwd.googlegroups .com>,
"Nick Vatamaniuc" <va******@gmail.comwrote:
Michael,
You only need to call the __init__ method of the superclass if you need
to do something special during initialization.
Hi, Nick,

Thank you for responding. I understand the purpose in invoking the
superclasses' __init__ methods. Let us take it as a given that I
require this behaviour; the simple example does not show it, but I am
using the same technique in a much more elaborate program, where in fact
the superclass initialization is required.
In general I just use the SuperClass.__init__(self,...) way of
calling the super class constructors.
Yes, and that certainly works just fine. But it obviates the point of
having super(). But perhaps that is the take-home message.

I do not want A's constructor to dispatch further along in the MRO for E
for two reasons: One, because the constructors along the (E D B) chain
take different argument lists (in my real code) than the (E C A) path;
and two, because I happen to care about the order in which the methods
are invoked.
In general note that __init__ is NOT a constuctor it is an initializer
Yes, you're right; I apologize for the imprecision. However, for the
purposes of this example, the distinction is irrelevant.

Cheers,
-M

--
Michael J. Fromberger | Lecturer, Dept. of Computer Science
http://www.dartmouth.edu/~sting/ | Dartmouth College, Hanover, NH, USA
Jul 19 '06 #7

P: n/a
Michael J. Fromberger wrote:
....
>
Of course, I could just bypass super, and explicitly invoke them as:

C.__init__(self, ...)
D.__init__(self, ...)

... but that seems to me to defeat the purpose of having super in the
first place.
As others have pointed out, super, is designed to do something different from
what you want. See
http://www.python.org/download/relea...o/#cooperation for GvR's
explanation of super's intent, limitations, and a pure-python implementation
that you might alter for your purposes.

Some people argue that effective use cases for super are rare and that it's
awkward to use correctly even in these cases. See for example,
http://fuhm.net/super-harmful/. So don't feel bad about not using it ;-)

Given what you assert about your inheritance graph (two independent ancestor
chains, that do not propagate super calls from their respective base classes),
what is objectionable about:
C.__init__(self, ...)
D.__init__(self, ...)
Michael
Jul 19 '06 #8

P: n/a
In article <ma***************************************@python. org>,
Michael Spencer <ma**@telcopartners.comwrote:
As others have pointed out, super, is designed to do something different from
what you want. See
http://www.python.org/download/relea...o/#cooperation for
GvR's
explanation of super's intent, limitations, and a pure-python
implementation
that you might alter for your purposes.
Indeed so. The documentation for super() led me to an erroneous
conclusion.
Given what you assert about your inheritance graph (two independent ancestor
chains, that do not propagate super calls from their respective base
classes),
what is objectionable about:
C.__init__(self, ...)
D.__init__(self, ...)
Well, since super() were much better labelled call_next_method, I must
agree that the Class.__init__(self, ...) form is probably the best
solution!

Thanks for your feedback.

Cheers,
-M

--
Michael J. Fromberger | Lecturer, Dept. of Computer Science
http://www.dartmouth.edu/~sting/ | Dartmouth College, Hanover, NH, USA
Jul 20 '06 #9

This discussion thread is closed

Replies have been disabled for this discussion.