There are a number of modules in PyPI that can help you with signature based overloading and dispatch: multipledispatch, multimethods, Dispatching - none of which I have real experience with, but multipledispatch
looks like what you want and it's well documented. Using your circle example:
from multipledispatch import dispatch
class Point(tuple):
pass
class Curve(object):
pass
@dispatch(Point, Point, Point)
def Circle(point1, point2, point3):
print "Circle(point1, point2, point3): point1 = %r, point2 = %r, point3 = %r" % (point1, point2, point3)
@dispatch(Point, int)
def Circle(centre, radius):
print "Circle(centre, radius): centre = %r, radius = %r" % (centre, radius)
@dispatch(Curve, Curve, Curve)
def Circle(curve1, curve2, curve3):
print "Circle(curve1, curve2, curve3): curve1 = %r, curve2 = %r, curve3 = %r" % (curve1, curve2, curve3)
>>> Circle(Point((10,10)), Point((20,20)), Point((30,30)))
Circle(point1, point2, point3): point1 = (10, 10), point2 = (20, 20), point3 = (30, 30)
>>> p1 = Point((25,10))
>>> p1
(10, 10)
>>> Circle(p1, 100)
Circle(centre, radius): centre = (25, 10), radius = 100
>>> Circle(*(Curve(),)*3)
Circle(curve1, curve2, curve3): curve1 = <__main__.Curve object at 0xa954d0>, curve2 = <__main__.Curve object at 0xa954d0>, curve3 = <__main__.Curve object at 0xa954d0>
>>> Circle()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/mhawke/virtualenvs/urllib3/lib/python2.7/site-packages/multipledispatch/dispatcher.py", line 143, in __call__
func = self.resolve(types)
File "/home/mhawke/virtualenvs/urllib3/lib/python2.7/site-packages/multipledispatch/dispatcher.py", line 184, in resolve
(self.name, str_signature(types)))
NotImplementedError: Could not find signature for Circle: <>
It's also possible to decorate instance methods, so you can provide multiple implementations of __init__()
, which is quite nice. If you were implementing any actual behaviour within the class, e.g. Circle.draw()
, you would need some logic to work out what values are available with to draw the circle (centre and radius, 3 points, etc). But as this is just to provide a set of bindings, you probably only need to call the correct native code function and pass on the parameters :
from numbers import Number
from multipledispatch import dispatch
class Point(tuple):
pass
class Curve(object):
pass
class Circle(object):
"A circle class"
# dispatch(Point, (int, float, Decimal....))
@dispatch(Point, Number)
def __init__(self, centre, radius):
"""Circle(Point, Number): create a circle from a Point and radius."""
print "Circle.__init__(): centre %r, radius %r" % (centre, radius)
@dispatch(Point, Point, Point)
def __init__(self, point1, point2, point3):
"""Circle(Point, Point, Point): create a circle from 3 points."""
print "Circle.__init__(): point1 %r, point2 %r, point3 = %r" % (point1, point2, point3)
@dispatch(Curve, Curve, Curve)
def __init__(self, curve1, curve2, curve3):
"""Circle(Curve, Curve, Curve): create a circle from 3 curves."""
print "Circle.__init__(): curve1 %r, curve2 %r, curve3 = %r" % (curve1, curve2, curve3)
__doc__ = '' if __doc__ is None else '{}\n\n'.format(__doc__)
__doc__ += '\n'.join(f.__doc__ for f in __init__.funcs.values())
>>> print Circle.__doc__
A circle class
Circle(Point, Number): create a circle from a Point and radius.
Circle(Point, Point, Point): create a circle from 3 points.
Circle(Curve, Curve, Curve): create a circle from 3 curves.
>>> for num in 10, 10.22, complex(10.22), True, Decimal(100):
... Circle(Point((10,20)), num)
...
Circle.__init__(): centre (10, 20), radius 10
<__main__.Circle object at 0x1d42fd0>
Circle.__init__(): centre (10, 20), radius 10.22
<__main__.Circle object at 0x1e3d890>
Circle.__init__(): centre (10, 20), radius (10.22+0j)
<__main__.Circle object at 0x1d42fd0>
Circle.__init__(): centre (10, 20), radius True
<__main__.Circle object at 0x1e3d890>
Circle.__init__(): centre (10, 20), radius Decimal('100')
<__main__.Circle object at 0x1d42fd0>
>>> Circle(Curve(), Curve(), Curve())
Circle.__init__(): curve1 <__main__.Curve object at 0x1e3db50>, curve2 <__main__.Curve object at 0x1d42fd0>, curve3 = <__main__.Curve object at 0x1d4b1d0>
<__main__.Circle object at 0x1d4b4d0>
>>> p1=Point((10,20))
>>> Circle(*(p1,)*3)
Circle.__init__(): point1 (10, 20), point2 (10, 20), point3 = (10, 20)
<__main__.Circle object at 0x1e3d890>
>>> Circle()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/mhawke/virtualenvs/urllib3/lib/python2.7/site-packages/multipledispatch/dispatcher.py", line 235, in __call__
func = self.resolve(types)
File "/home/mhawke/virtualenvs/urllib3/lib/python2.7/site-packages/multipledispatch/dispatcher.py", line 184, in resolve
(self.name, str_signature(types)))
NotImplementedError: Could not find signature for __init__: <>