如何检查可变参数可调用的参数是否全部属于某个子类?

问题描述 投票:0回答:1

这可能是一项艰难的任务。

假设我有一个类型

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 来说效果不佳。

python generics types mypy pyright
1个回答
0
投票

如果

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__"
© www.soinside.com 2019 - 2024. All rights reserved.