Python and generic programming
Delaney, Timothy C (Timothy)
tdelaney at avaya.com
Mon Nov 22 23:56:34 EST 2004
And now a version that works with multiple arguments ...
import itertools
def generic (genfunc):
speclist = []
def wrapf (*args):
typs = tuple(type(arg) for arg in args if not
isinstance(arg, type))
assert len(args) == len(typs)
for specfunc, specs, typs in speclist:
if len(args) != len(typs):
continue
for arg, spec, typ in itertools.izip(args, specs, typs):
if isinstance(spec, type):
if not isinstance(arg, typ):
break
elif (arg != spec) or (not isinstance(arg, typ)):
break
else:
return specfunc(*args)
return genfunc(*args)
wrapf.wrappedfunc = genfunc
wrapf.speclist = speclist
wrapf.func_name = genfunc.func_name
return wrapf
def specialised (genf, *specifiers):
try:
genf = genf.genfunc
except AttributeError:
pass
assert len(specifiers) == genf.wrappedfunc.func_code.co_argcount
def spd(specf):
assert len(specifiers) == specf.func_code.co_argcount
typs = []
for s in specifiers:
if isinstance(s, type):
typs.append(s)
else:
typs.append(type(s))
typs = tuple(typs)
genf.speclist[:0] = [(specf, specifiers, typs)]
return specf
spd.genfunc = genf
return spd
# For my US friends ;)
specialized = specialised
@generic
def some_function (arg):
print "generic - %r" % (arg,)
@specialised(some_function, int)
@specialised(some_function, long)
def some_specific_function(arg):
print "int-specific - %r" % (arg,)
@specialised(some_function, float)
def some_specific_function(arg):
print "float-specific - %r" % (arg,)
@specialised(some_function, 1)
@specialised(some_function, 1.0)
@specialised(some_function, 1L)
def some_specific_function(arg):
print "one-specific - %r" % (arg,)
@generic
def other_function (arg1, arg2):
print "generic - %r, %r" % (arg1, arg2)
@specialised(other_function, 1, object)
def other_specific_function (arg1, arg2):
print "1/object - %r, %r" % (arg1, arg2)
@specialised(other_function, int, float)
def other_specific_function (arg1, arg2):
print "int/float - %r, %r" % (arg1, arg2)
@specialised(other_function, 1, float)
def other_specific_function (arg1, arg2):
print "1/float - %r, %r" % (arg1, arg2)
@specialised(other_function, 1, 2.0)
def other_specific_function (arg1, arg2):
print "1/2.0 - %r, %r" % (arg1, arg2)
if __name__ == '__main__':
some_function('abc')
some_function(itertools)
some_function(123)
some_function(123L)
some_function(123.0)
some_function(1)
some_function(1.0)
some_function(1L)
print
other_function(2, 2)
other_function(1, 2.0)
other_function(1, 1.0)
other_function(2, 2.0)
other_function(1, 2)
In cases where more than one specialisation would match, the most
recently added will be used i.e. in the above, for other_function(1,
1.0) will use (int, float) even though (1, object) would also match. So
it's important to create functions in the correct order.
This is starting to get recipe-worthy - but I want to see what happens
with methods first ...
Tim Delaney
More information about the Python-list
mailing list