I've written a decorator for easily creating multiple dispatch functions:
from functools import wraps
def multi_dispatch(for_function):
"""
Returns a multiple dispatch version of the function.
The returned function doesn't allow keyword arguments.
>>> @multi_dispatch
... def foo(a, b):
... pass
...
>>> @foo.add
... def _foo(a: int, b: int, c : str = '33'):
... return a + b*3 + len(c)
...
>>> @foo.add
... def _foo(a: int, b: int, c = 3):
... return a + b*3 - c
...
>>> @foo.add
... def _foo(a: float, b: float):
... return a*2 - b
...
>>> foo(4, 5)
16
>>> foo(1.0, 2.0)
0.0
>>> foo(4, 5, 'loooong')
26
>>> foo(3, 4.5)
Traceback (most recent call last):
...
KeyError: (<class 'int'>, <class 'float'>)
"""
@wraps(for_function)
def decorated(*args):
return decorated.registry[tuple(type(i) for i in args)](*args)
decorated.registry = {}
def adder(func):
"""
Adds the supplied function to the multiple dispatch registry.
"""
code = func.__code__
args = code.co_varnames
annotations = func.__annotations__
types = tuple(annotations[a] for a in args if a in annotations)
decorated.registry[types] = func
return func
decorated.add = adder
return decorated
I'd like to read your comments about the code (efficiency, re-usability, etc.), documentation and everything else that you feel is worth noting.
Update: After fixing all the points listed in the choosen answer, I have created a new version.