numpy.ndarray 的类型提示/注释 (PEP 484)

Posted

技术标签:

【中文标题】numpy.ndarray 的类型提示/注释 (PEP 484)【英文标题】:Type hinting / annotation (PEP 484) for numpy.ndarray 【发布时间】:2016-06-10 23:27:52 【问题描述】:

是否有人为特定的numpy.ndarray 类实现了类型提示?

现在,我使用的是typing.Any,但如果有更具体的内容会更好。

例如,如果 NumPy 人员为他们的 array_like 对象类添加了 type alias。更好的是,在dtype 级别实现支持,以便支持其他对象以及ufunc。

【问题讨论】:

pypi.python.org/pypi/plac 可以使用 Py3 注释 - 填充 argparse 解析器。对于 Py2,它使用装饰器创建类似的 annocation 数据库。 typing 是 Py 3.5 的新手。许多 numpy 用户仍在使用 Py2。我的系统上有 3.5,但我没有为它安装 numpynumpy 开发人员不会为 Python 的前沿添加功能(@ 运算符除外) numpy 维护在 github 存储库中。看issuespull requests;注册并提交您自己的问题。可能还有另一个讨论开发问题的论坛,但我看的最多的是github 问题。 对于任何调查此问题的人 - 看起来这里有一个相关的解决方案:***.com/questions/52839427/… > 现在有...@Jasha 这张票是 4.5 年前由我作为 OP 开的。 【参考方案1】:

查看DataShape。它使用数据类型以及一些语法来确定输入和输出数组的大小。

【讨论】:

所以 DataShape 是 Numpy 替代品?不完全是我的想法,因为我使用的是 SciPy,它需要 Numpy,明确地。 DataShape 是一个描述。目前没有正式的函数注释,但到目前为止,如果你要构建函数注释,这是我见过的关于 Numpy 类型的最佳描述。是的,我建议在将函数注释引入 numpy 源之前创建一个新的模块名称并将其用作概念证明。 如何使用 DataShape?该文档详细说明了 DataShape 可以做什么,但我并没有真正找到任何具体示例来说明它如何用于 Python 中的类型提示。 这只是一个仅链接的答案。 It would be preferable在此添加该库的使用示例,并提供链接供参考。 感谢您的反馈。我可以在这周晚些时候更新。【参考方案2】:

更新

检查最近的 numpy 版本是否有新的 typing 模块

https://numpy.org/doc/stable/reference/typing.html#module-numpy.typing

过时的答案

看起来typing 模块是在以下位置开发的:

https://github.com/python/typing

numpy 的主要存储库位于

https://github.com/numpy/numpy

可以在以下位置跟踪 Python 错误和提交

http://bugs.python.org/

添加功能的通常方法是分叉主存储库,开发该功能直到它是防弹的,然后提交一个拉取请求。显然,在流程的各个阶段,您都需要其他开发人员的反馈。如果您不能自己进行开发,那么您必须说服其他人这是一个有价值的项目。

cython 有一种注解形式,用于生成高效的C 代码。


您在numpy 文档中引用了array-like 段落。注意它的typing 信息:

确定对象是否可以使用 array() 转换为 numpy 数组的一种简单方法是简单地以交互方式尝试它,看看它是否有效! (Python 方式)。

换句话说,numpy 开发人员拒绝被牵制。他们没有或不能用文字描述哪些类型的对象可以或不能转换为np.ndarray

In [586]: np.array('test':1)   # a dictionary
Out[586]: array('test': 1, dtype=object)

In [587]: np.array(['one','two'])  # a list
Out[587]: 
array(['one', 'two'], 
      dtype='<U3')

In [589]: np.array('one','two')  # a set
Out[589]: array('one', 'two', dtype=object)

对于你自己的函数,像这样的注释

def foo(x: np.ndarray) -> np.ndarray:

有效。当然,如果您的函数最终调用了一些通过asanyarray 传递其参数的numpy 函数(正如许多人所做的那样),那么这样的注释将是不完整的,因为您的输入可能是listnp.matrix 等.


在评估这个问题和答案时,请注意日期。 484 在当时是一个相对较新的 PEP,将其用于标准 Python 的代码仍在开发中。但看起来提供的链接仍然有效。

【讨论】:

您正在使用什么软件、编辑器或解释器来使用annotations?据我所知,在普通的 Python 3 中,一个函数得到一个 __annotations__ 字典,但解释器对它什么也不做。 您希望将typing 注释添加到现有的numpy 函数(包括np.array)中,还是只希望将注释添加到您自己的函数中更容易的类型? 我已将此答案标记为已接受的答案,但为了完整起见,我选择后者(在我自己的代码中输入提示,它使用 Numpy)。我完全赞成 Duck Typing,但是当您 可以 提供静态类型信息时,我不明白您为什么不这样做,如果只是用于静态代码分析(PyCharm 确实会警告不兼容的类型)。谢谢,@hpaulj! 因为打字模块只是提供提示,我创建了两个帮助标签纯粹是为了便于阅读,并注意它没有通过 mypy 静态类型检查。 def Vector(np_arr): return np_arr.ndim == 1 def Matrix(np_arr): return np_arr.ndim &gt; 1 。希望,它可以帮助某人。 形状怎么样?我可以添加诸如 def blah() -> np.ndarray(785) 之类的提示:但我不能添加第二个维度,例如 -> np.ndarray(785, 10)。有一个形状提示非常有帮助,并且可以使我的代码中产生不同维度数组的多个函数更加清晰。【参考方案3】:

我所做的只是将其定义为

Dict[Tuple[int, int], TYPE]

例如,如果你想要一个浮点数组,你可以这样做:

a = numpy.empty(shape=[2, 2], dtype=float) # type: Dict[Tuple[int, int], float]

从文档的角度来看,这当然不准确,但是为了分析正确的用法并使用 pyCharm 正确完成,它非常有用!

【讨论】:

这比使用np.ndarray 作为类型更糟糕【参考方案4】:

nptyping 为指定 numpy 类型提示增加了很多灵活性。

【讨论】:

【参考方案5】:

在我公司,我们一直在使用:

from typing import TypeVar, Generic, Tuple, Union, Optional
import numpy as np

Shape = TypeVar("Shape")
DType = TypeVar("DType")

class Array(np.ndarray, Generic[Shape, DType]):
    """  
    Use this to type-annotate numpy arrays, e.g. 
        image: Array['H,W,3', np.uint8]
        xy_points: Array['N,2', float]
        nd_mask: Array['...', bool]
    """
    pass

def compute_l2_norm(arr: Array['N,2', float]) -> Array['N', float]:
    return (arr**2).sum(axis=1)**.5

print(compute_l2_norm(arr = np.array([(1, 2), (3, 1.5), (0, 5.5)])))

我们实际上有一个 MyPy 检查器来检查形状是否有效(我们应该在某个时候发布)。唯一的问题是它不会让 PyC​​harm 高兴(即你仍然会收到讨厌的警告行):

【讨论】:

MyPy 检查器有什么更新吗?很想将它集成到我的环境中 这是好东西,谢谢分享。然而,nptyping 包 (github.com/ramonhagenaars/nptyping) 似乎在很大程度上概括了这一点。【参考方案6】:

Numpy 1.21 包含一个带有 NDArray 泛型类型的 numpy.typing 模块。


来自Numpy 1.21 docs:
numpy.typing.NDArray = numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]

np.ndarray[Any, np.dtype[+ScalarType]] 的通用版本。

可在运行时用于键入具有给定 dtype 和未指定形状的数组。

示例:

>>> import numpy as np
>>> import numpy.typing as npt

>>> print(npt.NDArray)
numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]

>>> print(npt.NDArray[np.float64])
numpy.ndarray[typing.Any, numpy.dtype[numpy.float64]]

>>> NDArrayInt = npt.NDArray[np.int_]
>>> a: NDArrayInt = np.arange(10)

>>> def func(a: npt.ArrayLike) -> npt.NDArray[Any]:
...     return np.array(a)

截至 2021 年 11 月 10 日,根据numpy/numpy#16544,对形状的支持仍在进行中。

【讨论】:

以上是关于numpy.ndarray 的类型提示/注释 (PEP 484)的主要内容,如果未能解决你的问题,请参考以下文章

NumPy ndarray dtype 的类型提示?

TypeError: 不支持的操作数类型 -: 'numpy.ndarray' 和 'numpy.ndarray'

NumPy Ndarray对象

无法将 NumPy 数组转换为张量(不支持的对象类型 numpy.ndarray)错误

numpy ndarray 交换多维数组(矩阵)的行/列

Python - 重复数据删除问题:TypeError:不可散列的类型:'numpy.ndarray'