Python 键入:根据函数参数声明 return 值类型

Python Typing: declare return value type based on function argument

假设我有一个将类型作为参数的函数和 return 那个类型的实例:

def fun(t):
    return t(42)

然后我可以调用它并获取所提供类型的对象:

fun(int)           # 42
fun(float)         # 42.0
fun(complex)       # (42+0j)
fun(str)           # "42"
fun(MyCustomType)  # something

该列表并不详尽,我希望能够使用具有适当构造函数的任何类型。

然后,我想为该函数添加类型提示。该函数的 return 值的类型提示应该是什么?


我试过 using simply t,因为 t 是一种类型:

def fun(t: type) -> t:
    return t(42)

但这不起作用:

main.py:1: error: Name 't' is not defined


suggests using a TypeVar:

from typing import TypeVar

T = TypeVar("T")

def fun(t: T) -> T:
    return t(42)

但这似乎不对,因为 T 表示一个类型,所以它表明类型本身是 returned,而不是它的实例。 Mypy 拒绝它:

main.py:6: error: "object" not callable


Using Any 显然可以,但我觉得它太模糊,没有传达意图:

from typing import Any

def fun(t: type) -> Any:
    return t(42)

您正在寻找 typing.Type,结果为:

from typing import TypeVar, Type

T = TypeVar("T", str, complex, float, int)

def fun(t: Type[T]) -> T:
    return t(42)

fun(int)
fun(float)
fun(complex)
fun(str)

请注意,您的类型变量需要受到限制,因为并非所有 Type 对象都接受参数,但您可以将其限制为一些与您的示例一样的对象。

TLDR:您需要一个 TypeVar 用于 return 类型的呼叫 t:

def fun(t: Callable[[int], R]) -> R:
    ...

这里对类型的限制太严格了。该函数接受任何接受整数的 Callable,函数的 return 类型是 Callable 的类型。这可以使用 return 类型的 TypeVar 指定:

from typing import Callable, TypeVar


R = TypeVar('R')  # the variable return type


def fun(t: Callable[[int], R]) -> R:
    return t(42)

fun(int)                            # Revealed type is 'builtins.int*'
fun(float)                          # Revealed type is 'builtins.float*'
reveal_type(fun(lambda x: str(x)))  # Revealed type is 'builtins.str*'

这也适用于类型,因为类型实例化是一个调用。

如果一个更复杂的签名,例如需要关键字参数,使用 Protocol(来自 typingtyping_extensions)。


请注意,如果明确只想将 42 传递给 Callable,则可以使用 Literal(来自 typingtyping_extensions)指定。

R = TypeVar('R')


def fun(t: Callable[[Literal[42]], R]) -> R:
    return t(42)

注意任何 Callable[[int], R] 类型的函数也满足 Callable[[Literal[42]], R].