Python键入: declare return value type based on function argument

标签 python python-3.x typing

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

def fun(t):
    return t(42)

然后,我可以调用它并获取提供的类型的对象:
fun(int)           # 42
fun(float)         # 42.0
fun(complex)       # (42+0j)
fun(str)           # "42"
fun(MyCustomType)  # something

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

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

我已经尝试过using simply t ,因为t是一种类型:
def fun(t: type) -> t:
    return t(42)

但这不起作用:

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



This answer建议using a 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



Using Any 显然有效,但是我觉得它太模糊了,没有传达意图:
from typing import Any

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

最佳答案

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 (来自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]

关于Python键入: declare return value type based on function argument,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60202691/

相关文章:

python-3.x - "PDF File has not been decrypted"问题在 PyPDF2 中仍然存在

python - Python 3.6 中的通用 NamedTuple

typescript - 将抽象类实现为类型

python - 如何在不在我的脚本中硬编码的情况下找到 msbuild 的位置?

python - 限制 map 正交投影的纬度延伸

python - 我应该如何从 with 语句返回有趣的值?

python - 即将到来的 MongoEngine 生日

python - Python 在添加两个变量时选择的默认值是多少?

android - 使用 buildozer kivy 的 800mb apk 文件

Vim 用户,你们的右手放在哪里?