【问题标题】:Python type annotation for identical, generic function signatures用于相同的通用函数签名的 Python 类型注释
【发布时间】:2020-08-27 04:36:39
【问题描述】:

typing.Callable 接受两个“参数”:参数类型和返回类型。对于任意参数,参数类型应该是 ...,或者是显式类型列表(例如,[str, str, int])。

有没有办法表示Callables 具有完全相同但任意的泛型签名?

例如,假设我想要一个接受函数并返回具有相同签名的函数的函数,如果我事先知道函数签名,我可以这样做:

def fn_combinator(*fn:Callable[[Some, Argument, Types], ReturnType]) -> Callable[[Some, Argument, Types], ReturnType]:
    ...

但是,我预先不知道参数类型,我希望我的组合器具有适当的通用性。我曾希望这会奏效:

ArgT = TypeVar("ArgT")
RetT = TypeVar("RetT")
FunT = Callable[ArgT, RetT]

def fn_combinator(*fn:FunT) -> FunT:
    ...

但是,解析器(至少在 Python 3.7 中)不喜欢 ArgT 排在第一位。 Callable[..., RetT] 是我能做的最好的吗?

【问题讨论】:

    标签: python generics type-annotation


    【解决方案1】:

    Python 3.10 之前的版本

    如果您根本不需要更改函数签名,则应将FuncT 定义为TypeVar

    FuncT = TypeVar("FuncT", bound=Callable[..., object])
    
    def fn_combinator(*fn: FuncT) -> FuncT:
        ...
    

    有没有一种方法可以表示具有完全相同但任意的泛型签名的可调用对象?

    与类型别名(例如:FuncT = Callable[..., RetT])不同,TypeVar 允许类型检查器推断参数和返回值之间的依赖关系,确保函数签名完全相同。

    但是,这种方法是完全有限的。使用FuncT 会导致难以正确键入返回的函数(请参阅this mypy issue)。

    def fn_combinator(*fn: FuncT) -> FuncT:
        def combined_fn(*args: Any, **kwargs: Any) -> Any:
            ...
    
        # return combined_fn  # Won't work. `combined_fn` is not guaranteed to be `FuncT`
        return cast(FuncT, combined_fn)
    

    由于 PEP 484 中引入的 Callable 的限制,这是我们在 Python 3.7 中所能做的最好的事情。

    ...只有参数参数列表([A,B,C])或省略号(表示“未定义的参数”)可以作为 typing.Callable 的第一个“参数”。 --- PEP 612


    Python 3.10+

    幸运的是,在 Python 3.10 中,可调用对象的类型注释将变得更加灵活,PEP 612 提出了typing.ParamSpec(所谓的“参数规范变量”)和typing.Concatenate。这扩展了 Callable 以支持注释更复杂的可调用对象。

    这意味着您将能够执行以下操作:

    P = ParamSpec("P")
    RetT = TypeVar("RetT")
    
    def fn_combinator(*fn: Callable[P, RetT]) -> Callable[P, RetT]:
        ...
    

    它还允许我们在不使用 cast 的情况下对返回的可调用对象进行完全类型检查:

    def fn_combinator(*fn: Callable[P, RetT]) -> Callable[P, RetT]:
        def combined_fn(*args: P.args, **kwargs: P.kwargs) -> RetT:
            ...
    
        return combined_fn
    

    请参阅发行说明here

    【讨论】:

      猜你喜欢
      • 2018-10-27
      • 1970-01-01
      • 2016-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多