Pydantic 1.10:Field选项不足时,如何用@validate_arguments添加自定义验证
Pydantic自定义验证的实现方式
1. @validate_arguments的恰当用法
用@validate_arguments装饰器给函数添加参数验证是符合Python风格的做法,它能直接结合类型提示和Pydantic的验证能力,让代码简洁直观。
基础用法
直接在函数上装饰,结合类型提示实现简单验证:
from pydantic import validate_arguments, ValidationError @validate_arguments def calculate_area(radius: float): if radius <= 0: raise ValueError("半径必须大于0") return 3.14 * radius ** 2 try: calculate_area(-5) except ValidationError as e: print(e)
结合Annotated与Field
如果需要更清晰的规则声明,可通过Annotated搭配Field把验证规则和类型注解绑定:
from pydantic import validate_arguments, Field from typing import Annotated @validate_arguments def calculate_area(radius: Annotated[float, Field(gt=0, description="半径必须大于0")]): return 3.14 * radius ** 2
2. Field规则不足时的处理
当Field的内置选项(如gt、lt、regex等)无法满足需求时,有两种常用方案:
函数内直接添加验证逻辑
适合简单的一次性验证,直接在函数内部抛出异常:
@validate_arguments def calculate_area(radius: float): if radius <= 0: raise ValueError("半径必须大于0") if radius > 100: raise ValueError("半径不能超过100") return 3.14 * radius ** 2
用AfterValidator抽离验证逻辑
如果验证逻辑需要复用,可将其封装成函数,通过AfterValidator注入到类型注解中:
from pydantic import validate_arguments, AfterValidator from typing import Annotated def check_radius(r: float) -> float: if r <= 0: raise ValueError("半径必须大于0") if r > 100: raise ValueError("半径不能超过100") return r @validate_arguments def calculate_area(radius: Annotated[float, AfterValidator(check_radius)]): return 3.14 * radius ** 2
3. 扩展Pydantic类型并重写验证逻辑
可以通过自定义类型扩展Pydantic的验证能力,这种方式推荐在验证逻辑需要多处复用的场景,避免重复代码。
自定义类型示例
from pydantic import GetCoreSchemaHandler from pydantic_core import core_schema from typing import Any class PositiveLimitedFloat(float): @classmethod def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: # 复用float类型的基础验证,再附加自定义逻辑 return core_schema.no_info_wrap_validator_function( cls.validate, handler(float), ) @classmethod def validate(cls, v: Any) -> float: if not isinstance(v, (int, float)): raise TypeError("必须传入数字类型") v = float(v) if v <= 0: raise ValueError("数值必须大于0") if v > 100: raise ValueError("数值不能超过100") return v # 直接使用自定义类型 @validate_arguments def calculate_area(radius: PositiveLimitedFloat): return 3.14 * radius ** 2
如果只是单个场景使用,这种方式会有点过度设计,优先选择更轻量的验证方案即可。
4. 其他实现方式
用Pydantic模型封装参数
当函数参数较多、验证规则复杂时,可将参数封装为Pydantic模型,通过field_validator定义验证逻辑:
from pydantic import BaseModel, field_validator class AreaRequest(BaseModel): radius: float @field_validator("radius") def check_radius(cls, v): if v <= 0: raise ValueError("半径必须大于0") if v > 100: raise ValueError("半径不能超过100") return v def calculate_area(req: AreaRequest): return 3.14 * req.radius ** 2 # 调用时直接传入模型实例或字典 calculate_area(AreaRequest(radius=5)) calculate_area({"radius": 10})
结合BeforeValidator/PlainValidator
BeforeValidator:用于在类型转换前预处理数据(如字符串转数字)PlainValidator:用于简单的无上下文验证逻辑
示例:
from pydantic import validate_arguments, BeforeValidator, PlainValidator from typing import Annotated def str_to_float(v: Any) -> float: if isinstance(v, str): return float(v.strip()) return v @validate_arguments def calculate_area(radius: Annotated[float, BeforeValidator(str_to_float), PlainValidator(lambda x: x > 0)]): return 3.14 * radius ** 2 # 支持传入字符串格式的数字 calculate_area("10")
内容的提问来源于stack exchange,提问作者coolio
相关产品推荐
相关产品推荐

