【问题标题】:Evaluating typehints for numpy.radians and float/array input elements评估 numpy.radians 和浮点/数组输入元素的类型提示
【发布时间】: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 整行。

标签: python numpy type-hinting mypy


【解决方案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: ...
    
    

    参考文献

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 2016-11-12
        • 1970-01-01
        • 2015-10-20
        • 2017-07-26
        • 2019-05-19
        • 2021-07-07
        • 1970-01-01
        • 1970-01-01
        • 2012-02-06
        相关资源
        最近更新 更多