python-codewars-solutions/function_overloading/overload.py

68 lines
2.1 KiB
Python

# https://www.codewars.com/kata/5f24315eff32c4002efcfc6a
import inspect
# https://docs.python.org/3.8/reference/datamodel.html#customizing-class-creation
# https://snarky.ca/unravelling-pythons-classes/
# https://gist.github.com/tmr232/c7214d62607ba1fc0e0a2e82d7e041cd
class DispatchProxy:
def __init__(self, name):
self.registry = {}
self.name = name
def register(self, f):
print(f"register {inspect.signature(f)}")
argcount = f.__code__.co_argcount
self.registry[argcount] = f
"""
def decorator(func):
argcount = f.__code__.co_argcount
self.registry[argcount] = f
return func
return decorator
"""
def __call__(self, *args):
argcount = len(args) + 1 # add 1 because the first argument of a method is "self"
if argcount in self.registry:
resolved = self.registry[argcount]
print(f"resolved: {resolved.__name__}{inspect.signature(resolved)}")
return resolved(self, *args)
else:
raise AttributeError(f"No matching function for args: {args}")
class MyNamespace(dict):
def __getitem__(self, key):
#(f"get {key}")
return super().__getitem__(key)
def __setitem__(self, key, value):
#sign = inspect.signature(value) if callable(value) else value
#print(f"set {key} {value}")
# already exists => overload
is_method = callable(value) and not value.__name__.startswith("__")
if is_method and key in self:
m = self[key]
if not isinstance(m, DispatchProxy):
m = DispatchProxy(self)
m.register(self[key])
m.register(value)
super().__setitem__(key, m)
else:
super().__setitem__(key, value)
class Meta(type):
@classmethod
def __prepare__(cls, name, bases):
return MyNamespace()
def __new__(cls, name, bases, dct):
x = super().__new__(cls, name, bases, dct)
return x
def __init__(self, name, bases, attrs):
super(Meta, self).__init__(name, bases, attrs)