Skip to content

Instantly share code, notes, and snippets.

@arunbear
Created March 26, 2020 17:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arunbear/caef7546d297c01fddbd3f671179bb70 to your computer and use it in GitHub Desktop.
Save arunbear/caef7546d297c01fddbd3f671179bb70 to your computer and use it in GitHub Desktop.
Multimethods in Python
# Example usage of https://www.artima.com/weblogs/viewpost.jsp?thread=101605
# with added commutativity
import itertools
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(f"no match for {types}")
return function(*args)
def register(self, types, function):
if types in self.typemap:
raise TypeError("duplicate registration")
for p in itertools.permutations(types):
self.typemap[p] = 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
class Rock():
pass
class Paper():
pass
class Scissors():
pass
def diag(t, ob1, ob2):
print(f'{ob1.__class__.__name__} vs {ob2.__class__.__name__}: {t} wins')
@multimethod(Paper, Rock)
def play(ob1, ob2):
diag('Paper', ob1, ob2)
@multimethod(Scissors, Paper)
def play(ob1, ob2):
diag('Scissors', ob1, ob2)
@multimethod(Rock, Scissors)
def play(ob1, ob2):
diag('Rock', ob1, ob2)
if __name__ == '__main__':
r = Rock()
p = Paper()
s = Scissors()
play(p, r)
play(r, p)
play(s, p)
play(r, s)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment