summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2015-07-20 11:12:42 +0200
committerMichele Simionato <michele.simionato@gmail.com>2015-07-20 11:12:42 +0200
commitcb0effeeb8800abf028c89a392684cb599fd8259 (patch)
tree6ed2d8326d82acab2181afbb751065c8d84c2380 /src
parentcc752587247ffe103bacfa86e84b5797959cd845 (diff)
downloadpython-decorator-git-cb0effeeb8800abf028c89a392684cb599fd8259.tar.gz
Multidispatch, initial implementation
Diffstat (limited to 'src')
-rw-r--r--src/decorator.py51
1 files changed, 51 insertions, 0 deletions
diff --git a/src/decorator.py b/src/decorator.py
index c7ed19e..18302eb 100644
--- a/src/decorator.py
+++ b/src/decorator.py
@@ -40,6 +40,7 @@ __all__ = ["decorator", "FunctionMaker", "contextmanager"]
import re
import sys
import inspect
+import itertools
if sys.version >= '3':
from inspect import getfullargspec
@@ -271,3 +272,53 @@ except ImportError: # Python >= 2.5
__call__ = __call__
contextmanager = decorator(ContextManager)
+
+
+# ######################### dispatch_on ############################ #
+
+# inspired from simplegeneric by P.J. Eby and functools.singledispatch
+def dispatch_on(*dispatch_args):
+ """
+ Factory of decorators turning a function into a generic function
+ dispatching on the given arguments.
+ """
+ assert dispatch_args, 'No dispatch args passed'
+ dispatch_str = '(%s,)' % ', '.join(dispatch_args)
+
+ def generic(func):
+
+ typemap = {(object,) * len(dispatch_args): func}
+
+ def register(*types):
+ "Decorator to register an implementation for the given types"
+ if len(types) != len(dispatch_args):
+ raise TypeError('Length mismatch: expected %d types, got %d' %
+ (len(dispatch_args), len(types)))
+
+ def dec(f):
+ typemap[types] = f
+ return f
+ return dec
+
+ def dispatch(dispatch_args, *args, **kw):
+ "Dispatcher function"
+ types = tuple(type(arg) for arg in dispatch_args)
+ try: # fast path
+ return typemap[types](*args, **kw)
+ except KeyError:
+ pass
+ _gettypemap = typemap.get
+ for types in itertools.product(*(t.__mro__ for t in types)):
+ f = _gettypemap(types)
+ if f is not None:
+ return f(*args, **kw)
+ # else call the default implementation
+ return func(*args, **kw)
+
+ return FunctionMaker.create(
+ func, 'return _f_({}, %(shortsignature)s)'.format(dispatch_str),
+ dict(_f_=dispatch), register=register, default=func,
+ typemap=typemap, __wrapped__=func)
+
+ generic.__name__ = 'dispatch_on' + dispatch_str
+ return generic