这可能是一项艰难的任务。
假设我有一个类型
JSON = Union[Mapping[str, "JSON"], Sequence["JSON"], str, int, float, bool, None]
我有一个功能
def memoize[**P, T: JSON](fn: Callable[P,T]) -> Callable[P,T]:
# ...make the function memoizable
return wrapped_fn
如何将 fn 的参数限制为 JSON 的子类型?或者,如果这不能静态完成,我如何在创建包装器之前在 memoize 中检查这一点?
我尝试为 ParamSpec 变量 **P 提供界限,但似乎尚未实现。我也尝试过 issubclass 但这对于 typehints 来说效果不佳。
如果
fn
具有任意签名,目前还没有办法做到这一点。我相信下一个最好的事情是在调用站点生成错误(请参阅
Pyright游乐场):
import collections.abc as cx
import typing as t
type JSON = cx.Mapping[str, JSON] | cx.Sequence[JSON] | str | int | float | bool | None
class _JSONOnlyCallable(t.Protocol):
def __call__(self, /, *args: JSON, **kwargs: JSON) -> JSON: ...
def memoize[F: cx.Callable[..., t.Any]](fn: F, /) -> F | _JSONOnlyCallable:
return fn
@memoize
def f(a: int, b: str, c: set[int]) -> str: ...
>>> f(1, "", {1, 2})
^^^^^^
pyright: Argument of type "set[int]" cannot be assigned to parameter "args" of type "JSON" in function "__call__"