Python 2.3.3 super() behaviour

Discussion in 'Python' started by Nicolas Lehuen, Apr 21, 2004.

  1. 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 ?)

    Regards,
    Nicolas
     
    Nicolas Lehuen, Apr 21, 2004
    #1
    1. Advertising

  2. Nicolas Lehuen

    Peter Otten Guest

    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
     
    Peter Otten, Apr 21, 2004
    #2
    1. Advertising

  3. 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" <> a écrit dans le message de
    news:c65fbo$1q4$05$-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
    >
    >
    >
     
    Nicolas Lehuen, Apr 21, 2004
    #3
  4. 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" <> a écrit dans le message
    de news:40864674$0$24834$...
    > 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" <> a écrit dans le message de
    > news:c65fbo$1q4$05$-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
    > >
    > >
    > >

    >
    >
     
    Nicolas Lehuen, Apr 21, 2004
    #4
  5. Nicolas Lehuen

    David Fraser Guest

    super is not going to be helpful here, so why not call the X.__init__
    functions explicitly?
    Since you *need* multiple __init__ calls from the multiply-inherited
    class, super isn't going to work...

    Nicolas Lehuen wrote:
    > 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" <> a écrit dans le message
    > de news:40864674$0$24834$...
    >
    >>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" <> a écrit dans le message de
    >>news:c65fbo$1q4$05$-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
    >>>
    >>>
    >>>

    >>
    >>

    >
    >
     
    David Fraser, Apr 21, 2004
    #5
  6. Ah, so there *is* more than one way to do it, then ? ;)

    What the example shows is that super(...).__init__ does make one call to
    each superclass' __init__, provided that those superclasses play nicely and
    use super() themselves (as Peter wrote). If one of the superclasses does not
    use super(), the 'magical' iteration over parent methods is interrupted,
    hence the need to put those bad guys at the end of the superclasses list in
    the class declaration.

    But you're right, David, the simplest way to get what I want is to
    explicitely call the superclasses' __init__. However, this would mean that
    super() is not as useful as it seems. I'd rather find a way to *always* use
    super() than have special cases for certain inheritance trees. In other
    words, I'd rather have only one way to do it :).

    Regards,
    Nicolas

    "David Fraser" <> a écrit dans le message de
    news:c65j4o$3me$...
    > super is not going to be helpful here, so why not call the X.__init__
    > functions explicitly?
    > Since you *need* multiple __init__ calls from the multiply-inherited
    > class, super isn't going to work...
    >
    > Nicolas Lehuen wrote:
    > > 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" <> a écrit dans le

    message
    > > de news:40864674$0$24834$...
    > >
    > >>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" <> a écrit dans le message de
    > >>news:c65fbo$1q4$05$-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
    > >>>
    > >>>
    > >>>
    > >>
    > >>

    > >
    > >
     
    Nicolas Lehuen, Apr 21, 2004
    #6
  7. Michele Simionato, Apr 21, 2004
    #7
  8. Nicolas Lehuen

    Josef Meile Guest

    Peter Otten wrote:
    > 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()

    Ok, this produces almost what the original poster wanted. You
    just have to invert the order of the base classes in All:

    >>>class All(D2, D1):

    .... pass
    ....

    then you will get:
    >>> All().test()

    base
    derived 1
    derived 2

    However, I don't understand jet why this doesn't print:

    base
    derived 1
    base
    derived 2

    The method test of Base is called just once? Why?
    I taught it was something like:

    All.test() -> D1.test() + D2.test()

    which is the same as:

    (Base.test() + print "derived 1") + (Base.test() + print derived 2")

    Thanks in advanced,
    Josef
     
    Josef Meile, Apr 21, 2004
    #8
  9. Nicolas Lehuen

    Peter Otten Guest

    Josef Meile wrote:

    > Peter Otten wrote:
    > > 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()

    > Ok, this produces almost what the original poster wanted. You
    > just have to invert the order of the base classes in All:
    >
    > >>>class All(D2, D1):

    > ... pass
    > ...
    >
    > then you will get:
    > >>> All().test()

    > base
    > derived 1
    > derived 2
    >
    > However, I don't understand jet why this doesn't print:
    >
    > base
    > derived 1
    > base
    > derived 2
    >
    > The method test of Base is called just once? Why?
    > I taught it was something like:
    >
    > All.test() -> D1.test() + D2.test()
    >
    > which is the same as:
    >
    > (Base.test() + print "derived 1") + (Base.test() + print derived 2")
    >
    > Thanks in advanced,
    > Josef


    Every instance has just one __dict__, so calling the same Base method twice
    would at best be redundant. The Python designers are a bit smarter than
    that and implemented "cooperative" methods for newstyle classes. See
    http://www.python.org/2.2/descrintro.html#cooperation for the details.

    Peter
     
    Peter Otten, Apr 21, 2004
    #9
  10. "Nicolas Lehuen" <> wrote in message news:<40864ea6$0$25528$>...
    >
    > 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.
    >


    I'm surprised that a built-in type doesn't work with super(). Was
    this a design decision, and if so why, or is this something that
    should be fixed?
     
    A. Lloyd Flanagan, Apr 21, 2004
    #10
  11. Nicolas Lehuen

    David Fraser Guest

    Hi Nicolas

    Another related idea:
    Use template functions when you have enough control over the objects:

    def A(base=object):
    class A(base):
    def __init__(self):
    print "A"
    super(A, self).__init__()
    return A

    def B(base=object):
    class B(base):
    def __init__(self):
    print "B"
    super(B, self).__init__()
    return B

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

    C()

    This is a bit different to multiple inheritance, but can have nice
    effects...

    David

    Nicolas Lehuen wrote:
    > Ah, so there *is* more than one way to do it, then ? ;)
    >
    > What the example shows is that super(...).__init__ does make one call to
    > each superclass' __init__, provided that those superclasses play nicely and
    > use super() themselves (as Peter wrote). If one of the superclasses does not
    > use super(), the 'magical' iteration over parent methods is interrupted,
    > hence the need to put those bad guys at the end of the superclasses list in
    > the class declaration.
    >
    > But you're right, David, the simplest way to get what I want is to
    > explicitely call the superclasses' __init__. However, this would mean that
    > super() is not as useful as it seems. I'd rather find a way to *always* use
    > super() than have special cases for certain inheritance trees. In other
    > words, I'd rather have only one way to do it :).
    >
    > Regards,
    > Nicolas
    >
    > "David Fraser" <> a écrit dans le message de
    > news:c65j4o$3me$...
    >
    >>super is not going to be helpful here, so why not call the X.__init__
    >>functions explicitly?
    >>Since you *need* multiple __init__ calls from the multiply-inherited
    >>class, super isn't going to work...
    >>
    >>Nicolas Lehuen wrote:
    >>
    >>>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" <> a écrit dans le

    >
    > message
    >
    >>>de news:40864674$0$24834$...
    >>>
    >>>
    >>>>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" <> a écrit dans le message de
    >>>>news:c65fbo$1q4$05$-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
    >>>>>
    >>>>>
    >>>>>
    >>>>
    >>>>
    >>>

    >
    >
     
    David Fraser, Apr 22, 2004
    #11
  12. Duh, so it was a FAQ...

    What's interesting in your post is the fact that super is in fact a class
    (not a builtin function), and that you can inherit from it to get the
    expected behaviour :

    http://groups.google.it/groups?hl=i...uper&btnG=Cerca&meta=group%3Dcomp.lang.python

    Maybe this should be the default behaviour ?

    Regards,
    Nicolas

    "Michele Simionato" <> a écrit dans le message de
    news:...
    > "Nicolas Lehuen" <> wrote in message

    news:<40863bd7$0$25528$>...
    > > Hi,
    > >
    > > I hope this is not a FAQ, but I have trouble understanding the behaviour

    of
    > > the super() built-in function.

    >
    > Maybe this thread on super will interest you:
    >
    >

    http://groups.google.it/groups?hl=i...er&btnG=Cerca&meta=group%3Dcomp.lang.python.*
    >
    >
    > Michele Simionato
     
    Nicolas Lehuen, Apr 22, 2004
    #12
    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,825
    Darryl Pierce
    Feb 24, 2005
  2. Fernando Rodriguez

    Getting the super class via the super() function

    Fernando Rodriguez, Nov 21, 2003, in forum: Python
    Replies:
    2
    Views:
    728
    Bob Willan
    Nov 22, 2003
  3. Raymond Hettinger

    Python's super() considered super!

    Raymond Hettinger, May 26, 2011, in forum: Python
    Replies:
    25
    Views:
    1,325
    Thomas Rachel
    May 28, 2011
  4. Michele Simionato

    Re: Python's super() considered super!

    Michele Simionato, May 27, 2011, in forum: Python
    Replies:
    0
    Views:
    398
    Michele Simionato
    May 27, 2011
  5. Michele Simionato

    Re: Python's super() considered super!

    Michele Simionato, May 27, 2011, in forum: Python
    Replies:
    0
    Views:
    430
    Michele Simionato
    May 27, 2011
Loading...

Share This Page