Python 2.3.3 super() behaviour

David Fraser davidf at sjsoft.com
Wed Apr 21 06:47:20 EDT 2004


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" <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