Python 2.3.3 super() behaviour

Nicolas Lehuen nicolas.lehuen at thecrmcompany.com
Wed Apr 21 06:36:22 EDT 2004


The only problem I have is that I want to build a multiple inheritance
involving an object which does not cooperate, namely :

class T(object):
    def __init__(self):
        super(T,self).__init__()

class  TL(list,object):
    def __init__(self)
        super(TL,self).__init__()

In this case, T.__init__ is not called, because list.__init__ does not use
super(). The only clean way to proceed is to change the inheritance order :
TL(T,list). This way, both constructors are called.

Here is another example which exhibits the behaviour :

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

class B(object):
    def __init__(self):
        print 'B'

class C(B,A):
    def __init__(self):
        super(C,self).__init__()
        print 'C'

class D(A,B):
    def __init__(self):
        super(D,self).__init__()
        print 'D'

>>> C()
B
C
<__main__.C object at 0x008F3D70>
>>> D()
B
A
D
<__main__.D object at 0x008F39F0>

The problem is that if you go further down the inheritance, the behaviour is
even more complicated :

class E(object):
    def __init__(self):
        super(E,self).__init__()
        print 'E'

class F(C,E):
    def __init__(self):
        super(F,self).__init__()
        print 'F'

class G(D,E):
    def __init__(self):
        super(G,self).__init__()
        print 'G'

>>> F()
B
C
F
<__main__.F object at 0x008F3D70>
>>> G()
B
A
D
G
<__main__.G object at 0x008F3EF0>

class H(E,C):
    def __init__(self):
        super(H,self).__init__()
        print 'H'

class I(E,D):
    def __init__(self):
        super(I,self).__init__()
        print 'I'

>>> H()
B
C
E
H
<__main__.H object at 0x008F3E30>
>>> I()
B
A
D
E
I
<__main__.I object at 0x008F3FD0>

So the conclusion is : never do that :). Another more constructive
conclusion would be : always put the most cooperative classes first in the
inheritance declaration, provided that it doesn't interfere with your needs.
A class which has an uncooperative ancestor is less cooperative than a class
which has only cooperative ancestors.

Regards,
Nicolas

"Nicolas Lehuen" <nicolas.lehuen at thecrmcompany.com> a écrit dans le message
de news:40864674$0$24834$afc38c87 at news.easynet.fr...
> OK, I get it now, thanks.
>
> super() method calls should only be used for method involved in
> diamond-shaped inheritance. This is logical since in this case the base
> classe (from which the diamond-shaped inheritance starts) defines the
> interface of the method.
>
> This solves another question I was asking myself about super() : "how can
it
> work when the method signature differ between B and C ?". Answer : the
> method signature should not change because polymorphic calls would be
> greatly endangered. The base class defines the signature of the method
which
> must be followed by all its children, this way super() can work properly.
>
> The base method signature is not enforced by Python, of course, but you'd
> better respect it unless you get weird result in polymorphic calls.
>
> Regards,
> Nicolas
>
> "Peter Otten" <__peter__ at web.de> a écrit dans le message de
> news:c65fbo$1q4$05$1 at news.t-online.com...
> > Nicolas Lehuen wrote:
> >
> > > Hi,
> > >
> > > I hope this is not a FAQ, but I have trouble understanding the
behaviour
> > > of the super() built-in function. I've read the excellent book 'Python
> in
> > > a Nutshell' which explains this built-in function on pages 89-90.
Based
> on
> > > the example on page 90, I wrote this test code :
> > >
> > > class A(object):
> > >     def test(self):
> > >         print 'A'
> > >
> > > class B(object):
> > >     def test(self):
> > >         print 'B'
> > >
> > > class C(A,B):
> > >     def test(self):
> > >         super(C,self).test()
> > >         print 'C'
> > >
> > > print C.__mro__
> > > c=C()
> > > c.test()
> > >
> > > The output is :
> > > (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,
<type
> > > 'object'>)
> > > A
> > > C
> > >
> > > Whereas I was expecting :
> > > (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,
<type
> > > 'object'>)
> > > A
> > > B
> > > C
> > >
> > > Was I wrong to expect this (based on what I've read ?)
> >
> > As soon as a test() method without the super(...).test() is reached, no
> > further test methods will be invoked. Only the first in the list of base
> > classes will be invoked. If I'm getting it right you have to do
something
> > like:
> >
> > class Base(object):
> >     def test(self):
> >         print "base"
> >
> > class D1(Base):
> >     def test(self):
> >         super(D1, self).test()
> >         print "derived 1"
> >
> > class D2(Base):
> >     def test(self):
> >         super(D2, self).test()
> >         print "derived 2"
> >
> > class All(D1, D2):
> >     pass
> >
> > All().test()
> >
> > Here all cooperating methods have a super() call, and the base class
acts
> as
> > a showstopper to prevent that Python tries to invoke the non-existent
> > object.test().
> >
> > Peter
> >
> >
> >
>
>





More information about the Python-list mailing list