[Python-Dev] Problem with super() usage

glyph at divmod.com glyph at divmod.com
Tue Jul 18 17:59:39 CEST 2006



On Tue, 18 Jul 2006 09:24:57 -0400, Jean-Paul Calderone <exarkun at divmod.com> wrote:
>On Tue, 18 Jul 2006 09:10:11 -0400, Scott Dial <scott+python-dev at scottdial.com> wrote:
>>Greg Ewing wrote:
>>> Guido van Rossum wrote:
>>>> In the world where cooperative multiple inheritance
>>>> originated (C++), this would be a static error.

>>> I wasn't aware that C++ had anything resembling super().
>>> Is it a recent addition to the language?

>>C++ has no concept of MRO, so "super()" would be completely ambiguous.

>I think this was Greg's point.  Talking about C++ and super() is
>nonsensical.

C++ originally specified multiple inheritance, but it wasn't "cooperative" in
the sense that super is.  In Lisp, though, where cooperative method dispatch
originated, call-next-method does basically the same thing in the case where
there's no next method: it calls "no-next-method" which signals a generic
error.

    http://www.lisp.org/HyperSpec/Body/locfun_call-next-method.html

However, you can write methods for no-next-method, so you can override that
behavior as appropriate.  In Python you might achieve a similar effect using a
hack like the one Greg suggested, but in a slightly more systematic way; using
Python's regular inheritance-based method ordering, of course, not bothering 
with multimethods.  Stand-alone it looks like an awful hack, but with a bit
of scaffolding I think it looks nice enough; at least, it looks like the Lisp
solution, which while potentially ugly, is complete :).

This is just implemented as a function for brevity; you could obviously use a
proxy object with all the features of 'super', including optional self,
method getters, etc.  For cooperative classes you could implement noNextMethod
to always be OK, or to provide an appropriate "null" value for a type map of
a method's indicated return value ('' for str, 0 for int, None for object, 
etc).

# ---cut here---

def callNextMethod(cls, self, methodName, *a, **k):
    sup = super(cls, self)
    method = getattr(sup, methodName, None)
    if method is not None:
        return method(*a, **k)
    else:
        return self.noNextMethod(methodName, *a, **k)

class NextMethodHelper(object):
    def noNextMethod(self, methodName, *a, **k):
        return getattr(self, "noNext_"+methodName)(*a, **k)

class A(object):
    def m(self):
        print "A.m"

class B(NextMethodHelper):
    def m(self):
        print "B.m"
        return callNextMethod(B, self, "m")

    def noNext_m(self):
        # it's ok not to have an 'm'!
        print "No next M, but that's OK!"
        return None

class C(B, A):
    def m(self):
        print "C.m"
        return callNextMethod(C, self, "m")


#>>> c = C()
#>>> c.m()
#C.m
#B.m
#A.m
#>>> b = B()
#>>> b.m()
#B.m
#No next M, but that's OK!


More information about the Python-Dev mailing list