I think Guide is thinking about typing and whatnot a lot lately, now
with a post one multimethods, which mostly the same as
double-dispatch. I.e., you choose a function implementation based on
the type of the arguments.
However, Guido uses a global registry of functions by name. I like
Phillip's technique for generic functions, which is to give these a
functions a richer interface that includes a decorator. Here's
an example of Guido's code converted to that:
@multimethod
def div(a, b):
"div a by b"
return a / b
class rational(object):
def __init__(self, num, denom):
self.num, self.denom = num, denom
def __repr__(self):
return '%s/%s' % (self.num, self.denom)
@div.types(rational, int)
def div_rat_int(r, i):
return rational(r.num, r.denom*i)
@div.types(int, rational)
def div_int_rat(i, r):
return rational(r.denom * i, r.num)
@div.types(rational, float)
def div_rat_float(r, f):
return r.num / (r.denom*f)
@div.types(float, rational)
def div_float_rat(f, r):
return f * r.denom / r.num
@div.types(rational, rational)
def div_rat_rat(r1, r2):
return rational(r1.num * r2.denom, r1.denom * r2.num)
Here's how it looks:
>>> half = rational(1, 2)
>>> half
1/2
>>> third = rational(1, 3)
>>> div(half, third)
3/2
>>> div(half, 2)
1/4
>>> div(half, 0.5)
1.0
>>> div(1, 2)
0
>>> div(1, half)
2/1
And here's the implementation (it's actually simpler than Guido's):
class multimethod(object):
def __init__(self, default):
self.default = default
self.name = default.__name__
self.__doc__ = default.__doc__
self.typemap = {}
def __call__(self, *args):
types = tuple(arg.__class__ for arg in args) # a generator expression!
function = self.typemap.get(types, self.default)
return function(*args)
def types(self, *types):
def decorator(func):
if types in self.typemap:
raise TypeError("duplicate registration")
self.typemap[types] = func
if func.__name__ == self.name:
# to avoid confusion by overwriting the multimethod function
return self
else:
return func
return decorator
The module is located online at
http://svn.colorstudy.com/home/ianb/recipes/multimethod.py