A decorator is essentially a wrapper that takes the wrapped function as an argument and returns another function.
As stated in the accepted answer, singledispatch
returns a wrapper
that takes the first argument as registered type - self
in instance methods.
As shown in that answer, in cases like this you can write another wrapper to monkey patch the decorator. But this kind of hacky fixes are not always the best option.
As with like any other function, you can call the wrapper and pass the arguments to it explicitly, which seems simpler, flatter and more readable to me if this kind of method overloading is only seldom made in a package.
from functools import singledispatch
class TestClass(object):
def __init__(self):
self.test_method = singledispatch(self.test_method)
self.test_method.register(int, self._test_method_int)
self.test_method.register(list, self._test_method_list)
def test_method(self, arg, verbose=False):
if verbose:
print("Let me just say,", end=" ")
print(arg)
def _test_method_int(self, arg):
print("Strength in numbers, eh?", end=" ")
print(arg)
def _test_method_list(self, arg):
print("Enumerate this:")
for i, elem in enumerate(arg):
print(i, elem)
if __name__ == '__main__':
test = TestClass()
test.test_method(55555)
test.test_method([33, 22, 11])
There's another module, multipledispatch
(not standard but included in Anaconda and without any non-standard dependencies) that, as the name already indicates and unlike singledispatch
, allows multimethods.
In addition to Dispatcher
objects, with singledispatch
-compatible syntaxis, it provides a dispatch
decorator which hides the creation and manipulation of these objects from the user.
The dispatch decorator uses the name of the function to select the
appropriate Dispatcher object to which it adds the new
signature/function. When it encounters a new function name it creates
a new Dispatcher object and stores name/Dispatcher pair in a namespace
for future reference.
For instance:
from types import LambdaType
from multipledispatch import dispatch
class TestClass(object):
@dispatch(object)
def test_method(self, arg, verbose=False):
if verbose:
print("Let me just say,", end=" ")
print(arg)
@dispatch(int, float)
def test_method(self, arg, arg2):
print("Strength in numbers, eh?", end=" ")
print(arg + arg2)
@dispatch((list, tuple), LambdaType, type)
def test_method(self, arg, arg2, arg3):
print("Enumerate this:")
for i, elem in enumerate(arg):
print(i, arg3(arg2(elem)))
if __name__ == '__main__':
test = TestClass()
test.test_method(55555, 9.5)
test.test_method([33, 22, 11], lambda x: x*2, float)