评估 numpy.radians 和浮点/数组输入元素的类型提示
Posted
技术标签:
【中文标题】评估 numpy.radians 和浮点/数组输入元素的类型提示【英文标题】:Evaluating typehints for numpy.radians and float/array input elements 【发布时间】:2022-01-14 10:53:57 【问题描述】:我有一个如下所示的函数:
import numpy as np
def test() -> None:
a = map(np.radians, (1.,2.,np.array([1,2,3])))
用 mypy 计算会返回错误信息
error: Argument 1 to "map" has incompatible type "ufunc"; expected "Callable[[object], Any]"
仅使用浮点数或仅数组作为map
的输入列表在这里没有问题,当输入列表/元组包含两种类型的对象时就会出现问题。在运行时,这也没有问题。
如何修改此函数以满足 mypy 的要求并使其类型安全?
【问题讨论】:
喜欢def test() -> None: f = np.radians # type: Any; a = map(f, (1., 2., np.array([1, 2, 3])))
?你只是想摆脱错误信息?
@ThomasWeller 有没有更好的方法来做到这一点?这是 numpy 固有的错误还是我可以正确完成的错误?
就个人而言,我正在使用 Pycharm。它也使用类型提示并给出警告,但它不像 mypy 那样严格。你为什么使用mypy?编写更好的代码还是由您的雇主强制执行?
@ThomasWeller 我们有一个软件,我们想让它类型安全,并为此目的使用 mypy。你会建议我们如何处理这个问题?为此添加新行或根本不注释整个函数是否有意义?
抱歉,我不是这方面的专家。让我们拭目以待其他人怎么说。我认为以下几点:a)您知道它不会出现运行时错误 b)它似乎更像是一个 numpy 问题,它如何声明方法而不是您的问题。例如。 def test() -> None: f = lambda x: np.radians(x); a = map(f, (1., 2., np.array([1, 2, 3])))
也不会有 mypy 报告,但您可能会失去性能(矢量化)。就 Sp 个人而言,我可能会选择# type: ignore
整行。
【参考方案1】:
这里的问题是 mypy 将 (1., 2., np.array([1,2,3]))
的元素类型推断为 object
(而不是您希望在这里的 Union[float, np.ndarray]
),这与 np.radians
不兼容。
您可以做的一种解决方法是为您的元组/列表提供一个与元组/列表和np.radians
的参数兼容的显式类型。例如:
from typing import Sequence, Union
import numpy as np
def test() -> None:
x: Sequence[Union[float, np.ndarray]] = (1., 2., np.array([1,2,3]))
a = map(np.radians, x)
有一个 open mypy github issue 看起来很相似,但也许 不完全相同:python/mypy#6697。
【讨论】:
【参考方案2】:恕我直言,正确的解决方案是告诉 MyPy 忽略这一行。
import numpy as np
def test() -> None:
a = map(np.radians, (1.,2.,np.array([1.,2.,3.]))) # type: ignore
PS:您总是有非常不明智的选择来编辑 numpy 库并修复 _UFunc_Nin1_Nout1
的调用签名以接受对象类型(除了 ArrayLike
)。下面的编辑使您的 mypy 错误消息消失。
--- a/typing/_ufunc.pyi
+++ b/typing/_ufunc.pyi
@@ -86,21 +86,21 @@ class _UFunc_Nin1_Nout1(ufunc, Generic[_NameType, _NTypes, _IDType]):
casting: _Casting = ...,
order: _OrderKACF = ...,
dtype: DTypeLike = ...,
subok: bool = ...,
signature: Union[str, _2Tuple[Optional[str]]] = ...,
extobj: List[Any] = ...,
) -> Any: ...
@overload
def __call__(
self,
- __x1: ArrayLike,
+ __x1: ArrayLike | object,
out: Union[None, NDArray[Any], Tuple[NDArray[Any]]] = ...,
*,
where: Optional[_ArrayLikeBool_co] = ...,
casting: _Casting = ...,
order: _OrderKACF = ...,
dtype: DTypeLike = ...,
subok: bool = ...,
signature: Union[str, _2Tuple[Optional[str]]] = ...,
extobj: List[Any] = ...,
) -> NDArray[Any] | Any: ...
参考文献
Readthedocs 上的 MyPy 文档,MyPy Common Issues and Solutions, Spurious errors and locally silencing the checker。type: ignore
是 PEP484 的一部分是有原因的。
Numpy _ufunc.py 声明了有问题的类型规范_UFunc_Nin1_Nout
、https://github.com/numpy/numpy/blob/main/numpy/typing/_ufunc.pyi
【讨论】:
【参考方案3】:我不知道是不是故意的,但你没有在数组中使用点。
import numpy as np
def test() -> None:
a = map(np.radians, (1.,2.,np.array([1.,2.,3.])))
【讨论】:
以上是关于评估 numpy.radians 和浮点/数组输入元素的类型提示的主要内容,如果未能解决你的问题,请参考以下文章