Skip to content

Instantly share code, notes, and snippets.

@spitz-dan-l
Last active June 8, 2017 14:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spitz-dan-l/32cd681650ab7dfe84e1 to your computer and use it in GitHub Desktop.
Save spitz-dan-l/32cd681650ab7dfe84e1 to your computer and use it in GitHub Desktop.
Advanced python multiple dispatch implementation very advanced
import random #definitely a good thing to see at the top of a multiple-dispatch implementation!
import abc
import itertools
class ArgValidator:
@classmethod
def validate(cls, *args, mro_distances=None):
if mro_distances is None:
mro_distances = []
#disqualify validation rules with the wrong number of arguments
if len(args) != len(mro_distances):
return None
#return the euclidean distance from the match to the origin in mro space!
return sum(d*d for d in mro_distances)**0.5
@classmethod
def mro_distance(cls, obj, C):
if issubclass(type(C), abc.ABCMeta):
virtual_mro = list(itertools.takewhile((lambda t: issubclass(t, C)), type(obj).__mro__))
distance = len(virtual_mro) - 1
if distance < 0:
distance = None
return distance
else:
try:
#number of levels up the mro chain for a match
return type(obj).__mro__.index(C)
except ValueError:
#disqualify if no match
return None
class Dispatcher:
def __init__(self):
self.impls = []
def register(self, *arg_types):
validators = []
for i, arg_type in enumerate(arg_types):
#dynamically create an ArgValidator subclass that validates whether a particular positional arg is an instance of a particular type!
ValidatorSubclass = type('{}_{}_validator'.format(arg_type.__name__, i), (ArgValidator,), {})
#inner function creates and returns a closure in order to avoid creating pseudo-closure variables via default arguments because that would be an abomination!
#note that no purpose is served by lexically nesting create_validate_method() inside of register()!
def create_validate_method(pos, arg_type, V):
@classmethod
def validate(cls, *args, mro_distances=None):
if mro_distances is None:
mro_distances = []
if pos >= len(args):
return None
mro_dist = cls.mro_distance(args[pos], arg_type)
if mro_dist is None:
return None
mro_distances.append(mro_dist)
#use cooperative multiple inheritance to determine whether other positional args validate!
return super(V, cls).validate(*args, mro_distances=mro_distances)
return validate
#monkey-patch dynamically-created subclass so that it has a reference to itself in its validate() method!
#(cooperative multiple inheritance doesn't work without the correct subclass passed as the first argument to super()!)
ValidatorSubclass.validate = create_validate_method(i, arg_type, ValidatorSubclass)
validators.append(ValidatorSubclass)
def wrapper(_impl):
#dynamically create a full validator class inheriting from multiple single-argument validator subclasses!
validator = type(_impl.__name__, tuple(validators), {})
self.impls.append((validator, _impl))
return _impl
return wrapper
def __call__(self, *args):
impl_distances = []
impls = []
#get the euclidean distance of all valid rules matching the input args!
for validator, impl in self.impls:
impl_dist = validator.validate(*args)
if impl_dist is not None:
impl_distances.append(impl_dist)
impls.append(impl)
#keep only the matching rules with lowest euclidean distance!
min_dist = min(impl_distances)
min_impls = [i for (d, i) in zip(impl_distances, impls) if min_dist == d]
if len(min_impls) == 1:
#no ambiguous match, go ahead and dispatch to the implementation!
return min_impls[0](*args)
elif len(min_impls) > 1:
#select one of the closest matches at random!
raise TypeError('Ambiguous dispatch') # return random.choice(min_impls)(*args)
raise NotImplementedError('Found no implementation for args {}'.format(', '.join(str(type(arg)) for arg in args)))
if __name__ == '__main__':
f = Dispatcher()
@f.register(int, int)
def _(a, b):
print('I got passed 2 ints')
@f.register(int, str)
def _(a, b):
print('I got passed an int and a str')
@f.register(int, int, str)
def _(a, b, c):
print('I got passed an int, an int and a str')
f(1, 2)
f(1, 'blarg')
f(1, 3, 'blarg')
class A: pass
class B(A): pass
@f.register(A, A)
def _(a1, a2):
print('I got passed 2 As')
@f.register(B, A)
def _(b1, b2):
print('I got passed a B and an A')
@f.register(A, B)
def _(a, b):
print('I got passed an A and a B')
f(A(), A())
f(A(), B())
f(B(), A())
# for i in range(10):
# #different each time!
# f(B(), B())
@f.register(B, B)
def _(b1, b2):
print('I got passed 2 Bs')
f(B(), B())
class C(metaclass=abc.ABCMeta):
pass
C.register(A)
@f.register(C)
def _(c):
print('I got a C')
f(A())
f(B())
class D(metaclass=abc.ABCMeta):
pass
D.register(B)
@f.register(D)
def _(d):
print('I got a D')
f(A())
f(B())
class E(metaclass=abc.ABCMeta):
@classmethod
def __subclasshook__(cls, other):
return hasattr(other, 'e_member')
A.e_member = 1
@f.register(E)
def _(e):
print('I got an E')
f(B())
@spitz-dan-l
Copy link
Author

This is from when I decided to try programming as performance art. It is a really strange implementation of multiple dispatch (https://en.wikipedia.org/wiki/Multiple_dispatch) in python. It combines a number of esoteric and strange approaches to accomplish this. Among them are:

  • A Euclidean Distance metric applied to python's __mro__ attribute to identify the most-specific implementation to dispatch to.
  • Completely unnecessary dynamic invocation of the type metaclass, combined with cooperative multiple inheritance and strategically chained super() calls to accomplish what a for loop could accomplish.
  • Choosing an implementation at random when there are multiple candidates for most-specific.

Do not use this for anything. Do not learn anything about programming from this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment