Since the release of python 3.7, it has been possible to do this using functools.singledispatch
.
from functools import singledispatch
@singledispatch
def greet(arg: object):
raise NotImplementedError(f"Don't know how to greet {type(arg)}")
@greet.register
def _(arg: str):
print(f"Hello, {arg}!")
@greet.register
def _(arg: int):
print(', '.join("Hello" for _ in range(arg)), "!")
greet("Bob") # string implementation is called — prints "Hello, Bob!"
greet(4) # int implementation is called — prints "Hello, Hello, Hello, Hello!"
greet(["Alice, Bob"]) # no list implementation, so falls back to the base implementation — will raise an exception
In the above example, a base implementation is registered that will raise NotImplementedError
. This is the "fallback" implementation that is returned if none of the other implementations is suitable.
Following the definition of the base implementation, an arbitrary number of type-specific implementations can be registered, as shown in the example — the function behaves completely differently depending on the type of the argument that is fed to it, and the @singledispatch
method uses type annotations to register a certain implementation of a function with a certain type
.
A singledispatch
function can have any number of arguments, but only the type annotation for the first argument is relevant to which implementation is called.