如何在Pydantic的float类型校验中过滤NaN值
Pydantic float字段过滤NaN值实现方案
Pydantic 默认不会拦截float('nan')这类特殊浮点值,因为NaN本身属于Python原生float类型范畴,要实现NaN的校验拦截或自动过滤,可直接通过字段校验器实现,适配所有主流Pydantic版本。
方案1:单字段校验(最灵活,推荐)
针对单个字段添加校验逻辑,可根据需求选择直接抛错拦截NaN,或者自动替换NaN为默认值实现过滤。
Pydantic V2 写法(当前主流版本)
import math from pydantic import BaseModel, field_validator class MySchema(BaseModel): float_value: float @field_validator("float_value") @classmethod def check_nan(cls, value: float) -> float: # 拦截NaN,抛出校验错误 if math.isnan(value): raise ValueError("浮点值不能为NaN") return value
如果需要自动过滤NaN、不抛错,直接把NaN替换为指定默认值(比如None、0),可调整校验逻辑,同时对应修改字段类型:
import math from typing import Optional from pydantic import BaseModel, field_validator class MySchema(BaseModel): # NaN会被替换为None,所以字段标记为Optional float_value: Optional[float] = None @field_validator("float_value") @classmethod def filter_nan(cls, value: float) -> Optional[float]: if isinstance(value, float) and math.isnan(value): # 遇到NaN直接返回默认值,完成异常值过滤 return None return value
Pydantic V1 兼容写法
如果使用1.x版本的Pydantic,把field_validator替换为validator即可,其余逻辑一致:
import math from pydantic import BaseModel, validator class MySchema(BaseModel): float_value: float @validator("float_value") def check_nan(cls, value: float) -> float: if math.isnan(value): raise ValueError("浮点值不能为NaN") return value
方案2:自定义通用类型(适合多字段复用)
如果项目中大量float字段都需要过滤NaN,不需要每个字段重复写校验器,可以自定义一个通用的非NaN浮点类型,全局复用:
import math from pydantic import BaseModel, GetCoreSchemaHandler from pydantic_core import core_schema from typing import Any class SafeFloat(float): """自动拦截NaN、无穷值的安全浮点类型""" @classmethod def __get_pydantic_core_schema__( cls, source_type: Any, handler: GetCoreSchemaHandler ) -> core_schema.CoreSchema: def validate(value: float) -> float: if math.isnan(value) or math.isinf(value): raise ValueError("浮点值不能为NaN或无穷值") return cls(value) return core_schema.no_info_plain_validator_function(validate) # 所有模型直接引用该类型即可,无需重复写校验逻辑 class MySchema(BaseModel): float_value: SafeFloat
注意事项
- 判断NaN优先使用
math.isnan(),不要依赖value != value的NaN特性判断,后者可读性差,还可能被自定义浮点类的等于方法重载逻辑干扰。 - 如果需要同时过滤正无穷、负无穷值,在校验逻辑中追加
math.isinf(value)判断即可。 - 校验器逻辑会在类型转换完成后执行,传入的字符串格式数字会先被Pydantic转为float,再进入NaN判断逻辑,无需额外处理类型转换。
内容的提问来源于stack exchange,提问作者Ryabchenko Alexander
相关产品推荐
相关产品推荐

