Python 类型:根据函数参数声明返回值类型



>假设我有一个函数,它将类型作为参数并返回该类型的实例:

def fun(t):
return t(42)

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

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

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

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


我尝试使用简单的t,因为t是一种类型:

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

但这不起作用:

main.py:1:错误:未定义名称"t">


这个答案建议使用TypeVar

from typing import TypeVar
T = TypeVar("T")
def fun(t: T) -> T:
return t(42)

但这似乎不对,因为T表示类型,因此它建议返回类型本身,而不是其实例。Mypy拒绝了它:

main.py:6:错误:"对象"不可调用


使用Any显然有效,但我觉得它太模糊了,它没有传达意图:

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

TLDR:您需要为调用t的返回类型TypeVar

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

在这里,对类型的约束过于严格。该函数接受任何采用整数的Callable,函数的返回类型是Callable的返回类型。这可以使用返回类型的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]

您正在寻找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对象都接受参数,但您可以将其限制为几个喜欢您的示例的对象。

最新更新