Dylan style multiple dispatch
#generic.py
#multimethods in python
#
#Example:
#>>> @generic(int)
#... def reverse(next_func, n):
#... return str(n)[::-1]
#...
#>>> @generic(str)
#... def reverse(next_func, s):
#... return s[::-1]
#...
#>>>reverse("hello")
#'olleh'
#>>>reverse(1234)
#4321
#Changes:
#31-Mar-2005: Fixed a bug in the dispatch, which ment
# that the best option might not be selected
# multiple inheritence situations.
_genericmethods = {}
def _issuitable(pts, pts_):
for pt, pt_ in zip(pts, pts_):
if not issubclass(pt, pt_):
return False
return True
def _closer(pts, (fn1, pts1), (fn2, pts2)):
for pt, pt1, pt2 in zip(pts, pts1, pts2):
mro = pt.mro()
score1 = mro.index(pt1)
score2 = mro.index(pt2)
if score1 < score2:
return (fn1, pts1)
if score2 < score1:
return (fn2, pts2)
return (fn1, pts1)
def generic(*paramtypes):
def generic_(func):
key = (func.__name__, len(paramtypes))
functions = _genericmethods.setdefault(key, [])
functions.append((func, paramtypes))
def next_method(suitable, params, pts):
if len(suitable)==0:
raise Exception, "Unable to match generic method"
else:
best = suitable[0]
for cur in suitable:
best = _closer(pts, best, cur)
suitable = suitable[:]
suitable.remove(best)
func, pts_ = best
return func(lambda *params:next_method(suitable, params, pts), *params)
def first_call(*params):
pts = [type(param) for param in params]
suitable = [(fn_, pts_)
for fn_, pts_ in functions
if _issuitable(pts, pts_)]
return next_method(suitable, params, pts)
return first_call
return generic_
0 Comments:
Post a Comment
<< Home