super() not a panacea?

Discussion in 'Python' started by Clarence Gardner, Feb 17, 2004.

  1. The super object is considered a solution to the "diamond problem".
    However, it generally requires that the ultimate base class know that it
    is last in the method resolution order, and hence it should not itself
    use super (as well as supplying the ultimate implementation of an
    overridden method.)

    However, a problem comes up if that ultimate base class is also the base
    class for another which inherits from it and another independent base
    class also providing that method. This results in a situation where the
    first base class is now required to use super in order to propogate the
    call chain over to the new classes, in the case of the object being an
    instance of the newly-added subclass, but still must not use super in
    the case of the object being an instance of the original (bottom of
    diamond) class.

    So, are we asking too much of super? Is there any resolution to this
    problem? The only one we can see is that a super object somehow effect a
    no-op when the search for a method ends with the "object" class (and
    "object", of course, doesn't implement the sought method). This seems
    yucky, though.


    print ' ',r'''Typical diamond using super.
    A
    / \
    B C
    \ /
    D
    '''

    class A(object):
    def m(self):
    print ' A'

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

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

    class D(B,C):
    def m(self):
    super(D, self).m()
    print ' D'

    print '''create D instance and call m'''

    D().m()

    print r'''A C B D, looks good. Now introduce classes Z & X
    A Z
    /|\ /
    / | \ /
    / | \/
    B C X
    \ /
    D
    '''

    class Z(object):
    def m(self):
    print ' Z'

    class X(A, Z):
    def m(self):
    super(X, self).m()
    print ' X'

    print '''create X instance and call m'''

    X().m()

    print '''"A X", Oh-oh, that is not right. Z.m was not called.
    That is because A is not calling super.
    Change class A to call super.'''

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

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

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

    class D(B,C):
    def m(self):
    super(D, self).m()
    print ' D'

    class Z(object):
    def m(self):
    print ' Z'

    class X(A, Z):
    def m(self):
    super(X, self).m()
    print ' X'

    X().m()

    print '"Z A X", That is much better.'
    print 'Now, make sure D still works as before.'

    try:
    D().m()
    except AttributeError, e:
    print ' Error:', e
    print ' ',"super object has no attribute 'm'!, now what?"
    Clarence Gardner, Feb 17, 2004
    #1
    1. Advertising

  2. "Clarence Gardner" <> wrote in message news:<>...
    > The super object is considered a solution to the "diamond problem".
    > However, a problem comes up if that ultimate base class is also the base
    > class for another which inherits from it and another independent base
    > class also providing that method.


    The solution I see is to introduce a placeholder base class Y
    with a dummy "m" method on top of the hierarchy:

    class Y(object):
    def m(self):
    pass

    class A(Y):
    def m(self):
    super(A, self).m()
    print ' A'

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

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

    class D(B,C):
    def m(self):
    super(D, self).m()
    print ' D'

    class Z(Y):
    def m(self):
    print ' Z'

    class X(A, Z):
    def m(self):
    super(X, self).m()
    print ' X'

    X().m()

    D().m()
    print X.mro()
    print D.mro()

    This is the easy solution. If you don't like it, let me know and I
    will show you other possibilities.

    Michele Simionato
    Michele Simionato, Feb 18, 2004
    #2
    1. Advertising

  3. Here is another solution that you will probably like more, since it does
    not require to change the hierarchy. The trick is to use a custom "super"
    which ignores attribute errors:

    class mysuper(super):
    def __getattribute__(self,name):
    try:
    return super.__getattribute__(self,name)
    except AttributeError: # returns a do-nothing method
    return lambda *args, **kw: None

    class A(object):
    def m(self):
    mysuper(A, self).m()
    print ' A'

    class B(A):
    def m(self):
    mysuper(B, self).m()
    print ' B'

    class C(A):
    def m(self):
    mysuper(C, self).m()
    print ' C'

    class D(B,C):
    def m(self):
    mysuper(D, self).m()
    print ' D'

    class Z(object):
    def m(self):
    print ' Z'

    class X(A, Z):
    def m(self):
    mysuper(X, self).m()
    print ' X'

    X().m()

    D().m()
    print X.mro()
    print D.mro()
    Michele Simionato, Feb 18, 2004
    #3
  4. Clarence Gardner

    John Roth Guest

    "Clarence Gardner" <> wrote in message
    news:p...
    >
    > The super object is considered a solution to the "diamond problem".
    > However, it generally requires that the ultimate base class know that it
    > is last in the method resolution order, and hence it should not itself
    > use super (as well as supplying the ultimate implementation of an
    > overridden method.)
    >
    > However, a problem comes up if that ultimate base class is also the base
    > class for another which inherits from it and another independent base
    > class also providing that method. This results in a situation where the
    > first base class is now required to use super in order to propogate the
    > call chain over to the new classes, in the case of the object being an
    > instance of the newly-added subclass, but still must not use super in
    > the case of the object being an instance of the original (bottom of
    > diamond) class.


    Have you reviewed the current method resolution order?

    http://www.python.org/2.3/mro.html

    I believe it was developed specifically to deal with this
    problem.

    Also, I'm firmly of the opinion that if you've got one of these
    bizzare cases, you've got a design smell that should be dealt
    with immediately, rather than expecting rational behavior from
    language facilities.

    "Rational," in this case, usually means "do what I need done
    in this specific case, regardless of what anyone else thinks."

    John Roth
    John Roth, Feb 18, 2004
    #4
    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,758
    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:
    719
    Bob Willan
    Nov 22, 2003
  3. Replies:
    7
    Views:
    450
    Patricia Shanahan
    Apr 6, 2008
  4. Hugh Sasse Staff Elec Eng

    Inheriting variables, super, and "not super"?

    Hugh Sasse Staff Elec Eng, Dec 9, 2003, in forum: Ruby
    Replies:
    7
    Views:
    122
    Hugh Sasse Staff Elec Eng
    Dec 11, 2003
  5. Replies:
    9
    Views:
    132
    Sean O'Halpin
    Jul 19, 2006
Loading...

Share This Page