Closed fsantini-vs closed 3 years ago
Supporting dispatching on defaults is difficult, but there is a workaround. Use overloading itself to specify defaults:
class A:
@multimethod
def m(self, c: int, ii: Optional[int]):
print('1', c, ii)
@multimethod
def m(self, c: int):
return self.m(c, None)
it seems not work for keyward argument?
it seems not work for keyward argument?
Keywords arguments are allowed but don't participate in the dispatch. As with defaults, it would be inefficient to implement. Instead of comparing tuples to types, the dispatch would have to compute the equivalent of Signature.bind for each call. Which is what overload
does.
Since you use return self[tuple(map(self.get_type, args))](*args, **kwargs)
to detect which func to call, I think it is a good choice to ignore keyword only argment when define multimethod.
For example
@multimethod
def f(int a, int b, *, int c, int d):
pass
will return multimethod {(<class int>, <class int>): <function>}
, instead of {(<class int>, <class int>, <class int>, <class int>): <function>}
This behavior is what "don't participate in the dispatch"
Since multimethod support python>=3.6, keyworld only argument is already supported. so this won't break consistency
It seems this change work
diff --git a/multimethod/__init__.py b/multimethod/__init__.py
index 1a11644..eca952c 100644
--- a/multimethod/__init__.py
+++ b/multimethod/__init__.py
@@ -25,7 +25,7 @@ def get_types(func: Callable) -> tuple:
annotations = dict(typing.get_type_hints(func))
annotations.pop('return', None)
params = inspect.signature(func).parameters
- return tuple(annotations.pop(name, object) for name in params if annotations)
+ return tuple(annotations.pop(name, object) for name in params if annotations and params[name].kind != inspect.Parameter.KEYWORD_ONLY)
class DispatchError(TypeError):
Maybe VAR_POSITIONAL
and VAR_KEYWORD
should also be ignore?
I create a pr(#19) for this
Seems like I misunderstood this request. I still think it's infeasible to dispatch on default and keywords arguments. But if the goal is simply to allow - and ignore - annotations on default and keyword parameters, that sounds reasonable.
Hi,
The following example produces an error: ` class A: @multimethod def m(self, c: int, ii: Optional[int] = None): print('1', c, ii)
obj = A() obj.m(20) `
when calling
obj.m(20)
: ` File "/usr/local/lib/python3.8/dist-packages/multimethod/init.py", line 184, in call return self[tuple(map(self.get_type, args))](*args, **kwargs) File "/usr/local/lib/python3.8/dist-packages/multimethod/init.py", line 180, in missing raise DispatchError(msg, types, keys) multimethod.DispatchError: ('a: 0 methods found', (<class 'main.A'>, <class 'int'>), [])Process finished with exit code 1 `
Is there a way around it?