寻找正确的Python类型提示,例如内置函数map()的签名。

7

描述

在 Python 3.5 或以上的版本中,支持类型提示(更多信息请参见此处)。然而,常用类型的正确用法并没有得到很好的记录。

例如,从官方网站上,我能够获得以下(适当的)用法:

字符串

# The function signature of greeting is: Callable[[str], str]
def greeting(name: str) -> str:
    return 'Hello ' + name

整数

# The function signature of add is: Callable[[int, int], int]
def add(a: int, b: int) -> int:
    return a + b

浮点数

# The default value of x is 1.0
def reciprocal(x: float = 1.0) -> float:
    from math import nan
    if x == 0:
        return nan
    return 1 / x

列表

from typing import List, TypeVar

T = TypeVar('T')

def repeat(x: T, n: int) -> List[T]:
    return [x] * n

元组

from typing import Tuple, TypeVar

T = TypeVar('T')

def double(x: T) -> Tuple[T, T]:
    return (x, x)

问题

我的问题是:

1. map 的返回类型是什么?

from typing import Iterable

# Is this correct?
x: Iterable[float] = map(int.__float__, [1, 2, 3])

我不确定上面的x是正确的类型提示。

2. 从更广泛的意义上讲,map的“函数签名”是什么?

from typing import Callable, Iterable, TypeVar

T = TypeVar('T')
U = TypeVar('U')

# In the above usage, the type of the map function seems to be:
Function1 = Callable[[T], U]
typeOfMap = Callable[[Function1, Iterable[T]], Iterable[U]]

# Or in one line:
typeOfMap = Callable[[Callable[[T], U], Iterable[T]], Iterable[U]]

但实际上,map函数可以接受多个可迭代对象。这在文档中有说明:

map(function, iterable, ...)

使用时可以这样:

# The result is: [['A'], ['B', 'B'], ['C', 'C', 'C']]
result = list(map(repeat, ['A', 'B', 'C'], [1, 2, 3]))

T1 = TypeVar('T1')
T2 = TypeVar('T2')
R = TypeVar('R')

# So, the type of map function in this usage seems to be:
Function2 = Callable[[T1, T2], R]
typeOfMap = Callable[[Function2, Iterable[T1], Iterable[T2]], Iterable[R]]

一般来说,我猜大概是下面这样,但这并不是正确的写法:
FunctionN = Callable[[T1, T2, ..., Tn], R]
typeOfMap = Callable[[FunctionN, Iterable[T1], Iterable[T2], ..., Iterable[Tn]], Iterable[R]]

那么,正确的写法是什么?

3.通常情况下,我在哪里可以找到Python函数/方法的正确类型提示,包括内置的以及核心库中的函数/方法?

我主要需要它们来学习。

4.有没有什么方法可以输出由编译器/解释器计算得出的类型推断结果,就像Haskell或Erlang一样?

我知道Haskell和Erlang是函数式编程语言,变量是不可变的,所以这将更容易实现,但如果Python也具有类似的功能,我想了解一下。

5.有没有办法检查我的类型提示是否正确?

或者至少让它在编译时/运行时显示一些警告/错误,以便我知道有问题。

参考资料

在撰写本文时,最新的稳定版本是3.8.0。

1个回答

6

1. map的返回类型是什么?

map的返回值当前被定义为Iterator[T]。由于迭代器也是可迭代对象,所以你可以这样注释:x: Iterable[float] = map(int.__float__, [1, 2, 3])(同时,你也可以直接写map(float, [1, 2, 3]))。

2. 更广义地说,map的“函数签名”是什么?

目前还无法表示,这就是为什么typeshed有超过6个泛型参数的重载。(相关问题

3. 一般来说,我在哪里可以找到Python函数/方法的正确类型提示,包括内置函数和核心库函数?

我的主要目的是为了学习。

Python的typeshed存储库。请注意,在进行学习目的的实践时,你通常应该让类型被推断出来,或者使用任何有意义的类型,而不是最精确的可能类型。

你也可以使用reveal_type——请参见下文。

4. 有没有办法输出编译器/解释器计算的类型推断结果,就像Haskell或Erlang一样?

我知道Haskell和Erlang是函数式编程语言,变量是不可变的,所以这将会更容易实现,但如果Python也有类似的功能,那就让我知道一下。

这取决于你的类型检查器。Mypy有reveal_type功能,请参见此处

x = map(float, [1, 2, 3])
reveal_type(x)  # note: Revealed type is 'typing.Iterator[builtins.float*]'

5. 如何确认我的类型提示是正确的?

或者至少让它在编译时/运行时显示警告/错误,以便我知道出了什么问题。

静态检查就是检查类型。例如,Mypy 会告诉你如果你的 x 提示有误。它不能捕获所有情况,特别是在 Python 这样的动态语言中,但这就是编程的本质。

有一些项目基于类型注解进行某些级别的运行时断言,但我没有使用过也不会真正费心去尝试。


非常感谢您的及时回复和出色的答案!如果我能给这个回答打分,它会得到“传奇”的评价!我对 Python 3 还比较陌生,不了解 mypy。我会去看一下的。对于那些想要使用 mypy 的人,这里是指向它的链接。 - Siu Ching Pong -Asuka Kenji-

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