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,但我没有为它安装 numpy
。 numpy
开发人员不会为 Python 的前沿添加功能(@
运算符除外)
numpy
维护在 github
存储库中。看issues
和pull 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
函数(正如许多人所做的那样),那么这样的注释将是不完整的,因为您的输入可能是list
或np.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 > 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 检查器来检查形状是否有效(我们应该在某个时候发布)。唯一的问题是它不会让 PyCharm 高兴(即你仍然会收到讨厌的警告行):
【讨论】:
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)的主要内容,如果未能解决你的问题,请参考以下文章
TypeError: 不支持的操作数类型 -: 'numpy.ndarray' 和 'numpy.ndarray'