如何对Python的list、array、series做仅含数值类型的类型检查?
解答
这类元素类型校验可以在静态类型检查层面实现大部分能力,仅运行时动态生成的输入场景需要结合单元测试或运行时校验补充。
首先先纠正你之前代码中的两处错误:
TypeVar定义语法错误:第一个参数必须是和变量名一致的字符串,其次numpy数组的类型注解应该用np.ndarray而非构造函数np.array。- 未给容器指定元素泛型参数,静态检查器本身就无法感知内部元素的类型要求。
实现方案:给容器指定元素泛型
现在主流的静态类型检查器(mypy、pyright等)都已原生支持list、numpy数组、pandas Series的带元素类型的泛型注解,改写后的代码如下:
from typing import TypeVar, Union import numpy as np import pandas as pd from numpy.typing import NDArray # 定义三类支持的数值型容器 NumericalList = list[Union[int, float]] NumericalNdarray = NDArray[Union[np.int_, np.float_]] NumericalSeries = pd.Series[Union[int, float]] # 定义泛型类型变量 T = TypeVar("T", NumericalList, NumericalNdarray, NumericalSeries) def average(x_lst: T) -> float: return sum(x_lst) / float(len(x_lst))
这种写法下,如果你传入list[str]、NDArray[np.bool_]这类非数值元素的容器,静态检查器会在开发阶段直接抛出类型错误,不需要运行代码。
如果希望支持所有符合「可迭代、可求长度、元素为数值」结构的类列表对象,不用限制死三类具体类型,可以用Protocol定义结构类型:
from typing import Protocol, Iterator, Union, TypeVar T_co = TypeVar("T_co", int, float, covariant=True) class NumericalListLike(Protocol[T_co]): def __iter__(self) -> Iterator[T_co]: ... def __len__(self) -> int: ... def average(x_lst: NumericalListLike[Union[int, float]]) -> float: return sum(x_lst) / float(len(x_lst))
静态类型检查的局限
静态检查只能覆盖开发阶段可以推导确定类型的场景,如果你的输入是运行时动态生成的(比如从外部文件读取的pd.Series、用户上传的列表),静态检查无法感知运行时的实际数据类型,这类场景需要补充:
- 简单的运行时类型校验(比如遍历检查元素类型,或用pydantic这类库做自动运行时校验)
- 覆盖动态输入场景的单元测试
内容的提问来源于stack exchange,提问作者CreekGeek
相关产品推荐
相关产品推荐

