如何正确检查变量是否为npt.ArrayLike类型实例
问题原因
npt.ArrayLike是numpy面向静态类型检查工具(mypy、pyright等)提供的泛型类型别名,本身不是实际存在的Python类,无法直接传入isinstance()做运行时类型校验,直接使用就会抛出Subscripted generics cannot be used with class and instance checks错误。
另外原代码还有一个隐蔽bug:抛出ValueError时没有加raise关键字,就算校验逻辑命中,异常也不会实际触发。
实现方案
要实现和bool、str、pd.DataFrame等常规类型一致的运行时校验逻辑,直接定义ArrayLike覆盖的合法类型元组,再传入isinstance()判断即可,同时保留原有的npt.ArrayLike类型注解供静态检查使用。
硬类型校验实现(和常规类型校验逻辑完全一致)
from typing import Optional import numpy as np import numpy.typing as npt import pandas as pd # 定义运行时可校验的ArrayLike类型集合,可根据业务需求增减类型 ARRAY_LIKE_TYPES = ( type(None), int, float, bool, complex, np.generic, list, tuple, range, np.ndarray, pd.Series, pd.DataFrame ) def func(data: Optional[npt.ArrayLike] = None) -> None: if not isinstance(data, ARRAY_LIKE_TYPES): raise ValueError(f"Keyword argument 'data' should be ArrayLike: got {type(data)}") # 业务逻辑代码 return None
更灵活的鸭子类型实现
如果不想硬编码第三方库的类型,想要兼容所有实现了numpy数组转换协议的对象,可以用特征判断代替硬类型校验:
from typing import Optional import numpy as np import numpy.typing as npt def is_array_like(obj) -> bool: if obj is None: return True # 判定规则:是内置标量/序列,或实现了numpy数组转换协议 return ( isinstance(obj, (int, float, bool, complex, list, tuple, range, np.generic)) or hasattr(obj, "__array__") ) def func(data: Optional[npt.ArrayLike] = None) -> None: if not is_array_like(data): raise ValueError(f"Keyword argument 'data' should be ArrayLike: got {type(data)}") # 业务逻辑代码 return None
这种写法会自动兼容所有符合numpy数组转换规范的自定义对象、pandas/xarray等第三方库的类数组结构,不需要手动维护类型列表。
内容的提问来源于stack exchange,提问作者user1494932
相关产品推荐
相关产品推荐

