64 lines
1.5 KiB
Python
64 lines
1.5 KiB
Python
from collections import defaultdict
|
|
from functools import wraps
|
|
|
|
def affinity(args):
|
|
def keyfunc(function):
|
|
return sum(arg == annotation for arg, annotation in zip(args[1:], function.__annotations__.values())) - len(function.__annotations__)
|
|
return keyfunc
|
|
|
|
|
|
def best_match(args, functions):
|
|
return max(functions, key=affinity(args))
|
|
|
|
|
|
def make_dispatcher(alternatives):
|
|
@wraps(alternatives[0])
|
|
def dispatch(*args, **kwargs):
|
|
return best_match(args, alternatives)(*args, **kwargs)
|
|
return dispatch
|
|
|
|
|
|
class MultiNamespaces(dict):
|
|
def __getitem__(self, key):
|
|
return super().__getitem__(key)[-1]
|
|
|
|
def __setitem__(self, key, value):
|
|
self.setdefault(key, []).append(value)
|
|
|
|
def to_dict(self):
|
|
frozen = {}
|
|
for key, values in self.items():
|
|
if callable(values[-1]):
|
|
frozen[key] = make_dispatcher(values)
|
|
else:
|
|
frozen[key] = values[-1]
|
|
return frozen
|
|
|
|
|
|
|
|
class Overloader(type):
|
|
@classmethod
|
|
def __prepare__(cls, name, bases, **kwds):
|
|
return MultiNamespaces()
|
|
|
|
def __new__(cls, name, bases, ns, **kwargs):
|
|
return super().__new__(cls, name, bases, ns.to_dict(), **kwargs)
|
|
|
|
|
|
class Overloading(metaclass=Overloader):
|
|
...
|
|
|
|
|
|
class Fib(Overloading):
|
|
def fib(self, n: 0):
|
|
return 1
|
|
|
|
def fib(self, n: 1):
|
|
return 1
|
|
|
|
def fib(self, n):
|
|
return self.fib(n - 1) + self.fib(n - 2)
|
|
|
|
|
|
print(Fib().fib(10))
|