# Python method overloading in a class
from functools import singledispatchmethod, singledispatch
class Foo:
@singledispatchmethod
def add(self, *args):
res = 0
for x in args:
res += x
print(res)
@add.register(str)
def _(self, *args):
string = ' '.join(args)
print(string)
@add.register(list)
def _(self, *args):
myList = []
for x in args:
myList += x
print(myList)
obj = Foo()
obj.add(1, 2, 3) # 6
obj.add('I', 'love', 'Python') # I love Python
obj.add([1, 2], [3, 4], [5, 6]) # [1, 2, 3, 4, 5, 6]
# for independent methods
from datetime import date, time
@singledispatch
def format(arg):
print(arg)
@format.register # syntax version 1
def _(arg: date):
print(f"{arg.day}-{arg.month}-{arg.year}")
@format.register(time) # syntax version 2
def _(arg):
print(f"{arg.hour}:{arg.minute}:{arg.second}")
format("today") # today
format(date(2021, 5, 26)) # 26-5-2021
format(time(19, 22, 15)) # 19:22:15
>>> from multipledispatch import dispatch
>>> from collections import namedtuple
>>> from types import * # we can test for lambda type, e.g.:
>>> type(lambda a: 1) == LambdaType
True
>>> Sprite = namedtuple('Sprite', ['name'])
>>> Point = namedtuple('Point', ['x', 'y'])
>>> Curve = namedtuple('Curve', ['x', 'y', 'z'])
>>> Vector = namedtuple('Vector', ['x','y','z'])
>>> @dispatch(Sprite, Point, Vector, int)
... def add_bullet(sprite, start, direction, speed):
... print("Called Version 1")
...
>>> @dispatch(Sprite, Point, Point, int, float)
... def add_bullet(sprite, start, headto, speed, acceleration):
... print("Called version 2")
...
>>> @dispatch(Sprite, LambdaType)
... def add_bullet(sprite, script):
... print("Called version 3")
...
>>> @dispatch(Sprite, Curve, int)
... def add_bullet(sprite, curve, speed):
... print("Called version 4")
...
>>> sprite = Sprite('Turtle')
>>> start = Point(1,2)
>>> direction = Vector(1,1,1)
>>> speed = 100 #km/h
>>> acceleration = 5.0 #m/s**2
>>> script = lambda sprite: sprite.x * 2
>>> curve = Curve(3, 1, 4)
>>> headto = Point(100, 100) # somewhere far away
>>> add_bullet(sprite, start, direction, speed)
Called Version 1
>>> add_bullet(sprite, start, headto, speed, acceleration)
Called version 2
>>> add_bullet(sprite, script)
Called version 3
>>> add_bullet(sprite, curve, speed)
Called version 4
#pip install danielutils
from danielutils import overload
class Foo:
def __init__(self):
pass
#'None' to skip
@overload(None, int)
def __add__(self, other):
return 1
@overload(None, str)
def __add__(self, other):
return 2
@overlaod(str,[int,float])
def bar(name,age):
return 3
@overload(str,str)
def bar(name,color):
return 4
if __name__ == '__main__':
print(Foo()+5) #-> 1
print(Foo()+"s") #-> 2
print(bar("jake",5)) #-> 3
print(bar("jake",5.5)) #-> 3
print(bar("jake","blue")) #-> 4
registry = {}
class MultiMethod(object):
def __init__(self, name):
self.name = name
self.typemap = {}
def __call__(self, *args):
types = tuple(arg.__class__ for arg in args) # a generator expression!
function = self.typemap.get(types)
if function is None:
raise TypeError("no match")
return function(*args)
def register(self, types, function):
if types in self.typemap:
raise TypeError("duplicate registration")
self.typemap[types] = function
def multimethod(*types):
def register(function):
name = function.__name__
mm = registry.get(name)
if mm is None:
mm = registry[name] = MultiMethod(name)
mm.register(types, function)
return mm
return register
###### usage ######
from multimethods import multimethod
# 'overload' makes more sense in this case
overload = multimethod
@overload(str, int)
def do_smth(a, b):
print(a + b)
@overload(str)
def do_smth(a):
print(a)