评估 numpy.radians 和 float/array 输入元素的类型提示

Evaluating typehints for numpy.radians and float/array input elements

我有一个如下所示的函数:

import numpy as np

def test() -> None:
    a = map(np.radians, (1.,2.,np.array([1,2,3])))

用 mypy 评估这个 returns 错误信息

error: Argument 1 to "map" has incompatible type "ufunc"; expected "Callable[[object], Any]"

仅使用浮点数或数组作为 map 的输入列表在这里没有问题,当输入 list/tuple 包含两种类型的对象时就会出现问题。在运行时这也没有问题。 如何修改此函数以满足 mypy 的要求并使其类型安全?

恕我直言,正确的解决方案是让 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: ...

参考资料

这里的问题是 mypy 将 (1., 2., np.array([1,2,3])) 的元素类型推断为 object(而不是你希望的 Union[float, np.ndarray]),这与np.radians.

您可以做的解决方法是为您的 tuple/list 提供一个与 tuple/list 和 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)

有一个开放的 mypy github 问题看起来很相似,但也许 不完全相同:python/mypy#6697.

不知道是不是故意的,你没有在数组中使用点。

import numpy as np

def test() -> None:
    a = map(np.radians, (1.,2.,np.array([1.,2.,3.])))