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

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

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

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)
python python-typing
3个回答
16
投票

TLDR:您需要一个

TypeVar
来表示调用的返回类型
t

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
(来自
typing
typing_extensions
)。


请注意,如果明确希望仅将

42
传递给
Callable
,则可以使用
Literal
(来自
typing
typing_extensions
)来指定。

R = TypeVar('R')


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

请注意,

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


11
投票

您正在寻找

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
对象都接受参数,但您可以将其限制为与您的示例类似的少数对象。


1
投票

上面你已经有了答案,但我再重复一遍:

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

我认为

type
可以从Python 3.10开始使用。之前是
Type

您可能想要这样的东西(将任何值转换为给定类型):

def fun(t: type[T], v) -> T:
  return t(v)
© www.soinside.com 2019 - 2024. All rights reserved.