68 lines
2.1 KiB
Python
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)
|