Python类型声明:基于函数参数声明返回值类型

21
假设我有一个函数,它以类型作为参数,并返回该类型的实例:
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: error: "object" not callable


使用Any显然可以工作,但我觉得它太模糊了,不能传达意图: (链接)
from typing import Any

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

相关问题:Python类的类型提示 - Stack Overflow ■ 顺便说一下,如果您不需要fun是一个函数,并且返回值是“自定义类”,您可能希望将该类定义为通用类,并像Fun[Union[int, float]]()这样调用它。 - user202729
出现错误"object" not callable是因为您将_instance_ t 作为函数使用。相反,您应该写成return type(t)(42)。否则,代码是正确的。语法-> T表示函数返回类型为T的_value_。 - undefined
3个回答

14

简述:在调用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]

9

您正在寻找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
谢谢,确实有效,但我觉得限制 T 太过于局限了。当然,我的函数并不能适用于每种类型,但我认为类型提示的工作不是“强制执行”它。特别是,我想在任何可以从 42 构造的东西上使用这个函数,包括用户定义的类。我会更新问题。 - el.pescado - нет войне

0
你已经在上面得到了答案,但我会重复一遍:
def fun(t: type[T]) -> T:
  return t(42)

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

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接