Search code examples
pythonpython-3.xsupermethod-resolution-orderfunctools

Equivalent to super() for functools.singledispatch


functools.singledispatch helps to define a single-dispatch generic method. Meanwhile, there is super() for calling methods or accessing attributes of a superclass.

Is there something like super() that can be used with singledispatch? I tried the following, but the result of super(Derived, value) is just not instance of Base, so it does not work as I expected:

from functools import singledispatch

@singledispatch
def hello(value):
    return ['default']

@hello.register(Base)
def hello_base(value):
    return hello(super(Base, value)) + ['base']

@hello.register(Derived)
def hello_derived(value):
    return hello(super(Derived, value)) + ['derived']

print(hello(Derived())
# expected ['default', 'base', 'derived'],
# but actually is ['default', 'derived'].

Solution

  • I believe that something like this will work, but I can't test it since I don't have Python 3.4 installed:

    def getsuperclass(cls):
        try:
            nextclass = cls.__mro__[1]
        except IndexError:
            raise TypeError("No superclass")
        return nextclass
    
    @singledispatch
    def hello(value):
        return ['default']
    
    @hello.register(Base)
    def hello_base(value):
        return hello.dispatch(getsuperclass(Base))(value) + ['base']
    
    @hello.register(Derived)
    def hello_derived(value):
        return hello.dispatch(getsuperclass(Derived))(value) + ['derived']
    
    print(hello(Derived()))
    

    Note that it doesn't really make sense to call hello with the superclass as the argument, because if you did that you would lose the original argument (value) that was passed. In your case it doesn't matter because your function doesn't use value at all, but a real dispatch function would probably actually do something with the value, so you need to pass the value as the argument.