我正在尝试编写协议以确保给定函数包含初始参数。如果我使协议定义仅支持该单个参数,mypy 会很高兴,但是当我添加
*args
和 **kwargs
以支持其他任意参数时,mypy 会抱怨。
from typing import Protocol, TypeVar, Dict, Any
T = TypeVar("T", covariant=True)
class Func(Protocol[T]):
def __call__(self, ctx: Dict[Any, Any], *args: Any, **kwargs: Any) -> T:
pass
def f(ctx: Dict[Any, Any]) -> str:
return "hello"
def ff(ctx: Dict[Any, Any], *args: Any, **kwargs: Any) -> str:
return "hello"
a: Func[str] = f # mypy complains here
b: Func[str] = ff # but not here
这可能吗?或者有没有办法告诉 mypy 只检查第一个参数而不检查其余参数的存在?
我不想使用
Callable[..., T]
因为它不强制执行 ctx
参数。
-- 编辑
我正在寻找这种行为:
def f(ctx: Dict[Any, Any]) -> str:
return "hello"
def ff(ctx: Dict[Any, Any], x: int) -> str:
return "hello"
def fff(ctx: Dict[Any, Any], x: int = 0) -> str:
return "hello"
def ffff(x: int) -> str:
return "hello"
a: Func[str] = f # yes
b: Func[str] = ff # yes
c: Func[str] = fff # yes
d: Func[str] = ffff # no
函数定义可以包含任意数量的附加参数,只要第一个参数是
Dict
.
Mypy 抱怨是因为如果一个变量的类型是
Func[str]
:
a: Func[str] = f
那么逻辑上你应该能够做到:
a({'the answer': 42}, 1, 2, 3, other_stuff="hello")
因为
Func
的接口指定它接受任意参数。
你的
f
函数没有,所以它不符合 Func
.
你真正想做的是使
Func
more的签名更严格:
class Func(Protocol[T]):
def __call__(self, ctx: Dict[Any, Any]) -> T:
pass
f
和ff
都可以用这个签名调用,所以他们都符合Func
.