升级至NumPy 1.22后出现新的mypy类型检查错误求助
NumPy 1.22.4升级后mypy 0.910类型检查报错的解决方案确认
把NumPy从1.21升级到1.22.4后,原本能通过mypy 0.910类型检查的代码出现了三类新错误,以下是错误分析、现有处理的正确性验证及更优方案:
1. 类型错误:signedinteger[_8Bit]不可索引
报错场景
x: np.ndarray v: float # mypy报错:error: Value of type "signedinteger[_8Bit]" is not indexable xn = np.int8(np.sign(np.atleast_1d(x).ravel() - v)) xn[0] # mypy无报错 xn = np.array(np.sign(np.atleast_1d(x).ravel() - v), dtype=np.int8) xn[0]
原因分析
NumPy 1.22优化了类型注解,np.int8()作为构造函数时,若传入标量会返回np.int8标量类型(而非数组)。当np.sign()的计算结果为标量时,np.int8()就会返回不可索引的标量,触发mypy报错。而np.array(..., dtype=np.int8)会强制返回数组类型,符合后续索引操作的类型要求。
方案确认与优化
现有处理方式是正确的。更简洁的替代方案可以用astype直接转换数组类型,避免额外的数组构造:
xn = np.sign(np.atleast_1d(x).ravel() - v).astype(np.int8) xn[0]
2. 赋值类型不兼容:float与floating[Any]类型不匹配
报错场景
import numpy as np def get_my_float(flt: float) -> float: return flt # mypy报错:error: Incompatible types in assignment (expression has type "float", variable has type "floating[Any]") get_my_float(np.average([2, 3])) # mypy无报错(临时解决方案) get_my_float(float(np.average([2, 3])))
原因分析
NumPy 1.22将np.average()的返回类型细化为np.floating[Any],而mypy 0.910认为Python原生float与NumPy浮点类型属于不同的类型体系,因此触发类型不兼容报错。
方案确认与优化
现有通过float()强制转换的方式是可行的。另外两种替代方案:
- 使用类型转换注解:
from typing import cast get_my_float(cast(float, np.average([2, 3]))) - 升级mypy到较新版本(如0.990+),新版本对NumPy类型的兼容性更好,可能自动识别
np.floating[Any]与原生float的兼容关系。
3. 返回值错误:assert_approx_equal无返回值
报错场景
import numpy as np # 计算参考解ref # 计算近似解app # mypy报错 np.testing.assert_approx_equal(app, ref) # 临时解决方案:抑制报错 np.testing.assert_approx_equal(app, ref) # type: ignore
原因分析
这是NumPy与mypy的已知兼容性问题,np.testing模块中的断言函数的类型注解存在缺陷,导致mypy错误地检测到返回值相关问题。
方案确认
目前使用# type: ignore抑制报错是最直接的解决方案。如果项目中测试文件单独管理,也可以配置mypy忽略测试目录的类型检查,避免逐个添加注解。
内容的提问来源于stack exchange,提问作者Pietro D'Antuono
相关产品推荐
相关产品推荐

