如何让Pydantic对整数Literal类型执行默认类型强制转换?
如何让Pydantic对Literal类型执行类型强制转换?
我正在用Pydantic的@validate_call装饰器验证函数输入,代码如下:
from typing import Literal from pydantic import validate_call @validate_call def foo(a: Literal[0, 90, 180, 270]) -> None: print(a, type(a))
我希望Pydantic能像处理int类型一样执行默认的类型强制转换:
foo(90) # 按预期工作 foo('90') # 无法工作,但我希望它能正常运行
如果用a: int作为注解,它会对'180'这类字符串进行强制转换,但之后我得手动验证输入的整数是否符合要求。
注:我接受要求a为字符串类型的解决方案,只要它仍允许整数和字符串输入。
不接受的解决方案
- 不想添加所有字面量情况。
Literal[0, 90, 180, 270, '0', '90', '180', '270']不可行,因为它不允许'-0'或'180.0'这类字符串。 - 可以用
Annotated[int, Field(ge=0, le=0)] | Annotated[int, Field(ge=90, le=90)] | ...,但这太冗长。 - 不想定义单独的函数或模型。到那种程度,还不如直接接受
a: int并在方法内手动验证具体值。
解决方案
可以用Annotated结合BeforeValidator,先将输入强制转换为整数,再用Literal验证是否符合要求。这样既保留了类型强制转换的能力,又不用手动写验证逻辑:
from typing import Literal, Annotated from pydantic import validate_call, BeforeValidator @validate_call def foo(a: Annotated[Literal[0, 90, 180, 270], BeforeValidator(lambda v: int(v))]) -> None: print(a, type(a))
测试效果:
foo(90) # 输出:90 <class 'int'>,正常工作 foo('90') # 输出:90 <class 'int'>,正常运行 foo('180.0') # 输出:180 <class 'int'>,可处理带小数的数字字符串 foo('-0') # 输出:0 <class 'int'>,符合要求
核心逻辑是通过BeforeValidator在Pydantic执行Literal验证前,把任意可转换为int的输入(字符串形式数字、带小数的数字字符串等)转换成整数,之后再检查转换后的数值是否在指定的Literal集合中。如果需要复用转换逻辑,也可以把lambda换成单独定义的函数:
def coerce_to_int(v): return int(v) @validate_call def foo(a: Annotated[Literal[0, 90, 180, 270], BeforeValidator(coerce_to_int)]) -> None: print(a, type(a))
这个方案简洁满足需求,不需要额外定义模型或冗长的注解。
内容的提问来源于stack exchange,提问作者kviLL
相关产品推荐
相关产品推荐

