从其他函数的注释推断返回类型注释

Mar*_*ler 2 python python-typing

我有一个带有复杂返回类型注释的函数:

\n
from typing import (Union, List)\n\n# The -> Union[\xe2\x80\xa6] is actually longer than this example:\ndef parse(what: str) -> Union[None, int, bool, float, complex, List[int], List[float], List[complex]]:\n  # do stuff and return the object as needed\n\ndef parse_from_something(which: SomeType) -> ????:\n  return parse(which.extract_string())\n\n# \xe2\x80\xa6\n\nclass SomeType:\n  def extract_string(self) -> str:\n     # do stuff and return str\n
Run Code Online (Sandbox Code Playgroud)\n

如何进行类型注释,parse_from_something以便注释后返回与以下内容相同的类型parse,而不重复它们?

\n

我在这里解决的问题是一个函数可能会发生变化,但它周围的包装器总是返回相同的类型集。我不想重复代码,并且因为这是重构和事后类型注释工作,所以我需要假设我将来会删除可能的返回类型parse,而静态类型检查器可能不会意识到parse_from_something不能再退回这些了。

\n

Bri*_*ian 5

这可以使用一些类型变量和装饰器来将特定的返回类型插入到函数的参数规范中。

从以下设置开始:

from typing import ParamSpec, TypeVar, Union, List, Any, Callable

P = ParamSpec("P")
R = TypeVar("R")

def parse(
    what: str,
) -> Union[None, int, bool, float, complex, List[int], List[float], List[complex]]:
    ...

def identity(x: R) -> R:
    return x

def returns_like(func: Callable[..., R]) -> Callable[[Callable[P, Any]], Callable[P, R]]:
    return identity
Run Code Online (Sandbox Code Playgroud)

然后您可以定义parse_from_something

@returns_like(parse)
def parse_from_something(which: Any) -> Any:
    return parse(which.extract_string())

reveal_type(parse_from_something)
reveal_type(parse_from_something(123))
Run Code Online (Sandbox Code Playgroud)

mypy --strict这通过了和下的类型检查pyright,并输出以下显示类型:

# mypy --strict
note: Revealed type is "def (which: Any) -> Union[None, builtins.int, builtins.float, builtins.complex, builtins.list[builtins.int], builtins.list[builtins.float], builtins.list[builtins.complex]]"
note: Revealed type is "Union[None, builtins.int, builtins.float, builtins.complex, builtins.list[builtins.int], builtins.list[builtins.float], builtins.list[builtins.complex]]"
Success: no issues found in 1 source file

# pyright
information: Type of "parse_from_something" is "(which: Any) -> (int | bool | float | complex | List[int] | List[float] | List[complex] | None)"
information: Type of "parse_from_something(123)" is "int | bool | float | complex | List[int] | List[float] | List[complex] | None"
0 errors, 0 warnings, 2 informations 
Run Code Online (Sandbox Code Playgroud)

自己在线尝试一下:mypy PlaygroundPyright Playground

在的内部parse_from_something,您的类型检查器将无法验证您返回的任何内容是否与 的返回类型兼容parse。例如,如果您添加了return {},您的类型检查器将保持沉默,而不是将其标记为类型错误。您承担确保parse_from_something行为良好的责任。


typing.TypeVarPS 如果您使用的是没有或 的旧版本 Python typing.ParamSpec,您可以使用typing-extensions向后移植它们。或者,如果您使用的是 Python 3.12+,则可以将它们替换为PEP 695 类型参数语法